diff options
author | Sergei Golubchik <serg@mariadb.org> | 2019-09-06 11:53:10 +0200 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2019-09-06 11:53:10 +0200 |
commit | 244f0e6dd815b388282c15db4fe7f15533f4c8fc (patch) | |
tree | af138f2b3739a742c0c38173cdc86ec176fc0edd /storage/innobase/lock | |
parent | 18af13b88ba580562981a190c25da128a2e9db26 (diff) | |
parent | 2842c369851a8afc2a944ce6f4f60fa052f20969 (diff) | |
download | mariadb-git-244f0e6dd815b388282c15db4fe7f15533f4c8fc.tar.gz |
Merge branch '10.3' into 10.4
Diffstat (limited to 'storage/innobase/lock')
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 236 |
1 files changed, 69 insertions, 167 deletions
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index aebbf5c1cab..3bf7e33fe4e 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4270,23 +4270,17 @@ lock_check_dict_lock( } #endif /* UNIV_DEBUG */ -/*********************************************************************//** -Releases transaction locks, and releases possible other transactions waiting -because of these locks. */ -static -void -lock_release( -/*=========*/ - trx_t* trx) /*!< in/out: transaction */ +/** Release the explicit locks of a committing transaction, +and release possible other transactions waiting because of these locks. */ +void lock_release(trx_t* trx) { - lock_t* lock; ulint count = 0; trx_id_t max_trx_id = trx_sys.get_max_trx_id(); - ut_ad(lock_mutex_own()); + lock_mutex_enter(); ut_ad(!trx_mutex_own(trx)); - for (lock = UT_LIST_GET_LAST(trx->lock.trx_locks); + for (lock_t* lock = UT_LIST_GET_LAST(trx->lock.trx_locks); lock != NULL; lock = UT_LIST_GET_LAST(trx->lock.trx_locks)) { @@ -4326,6 +4320,8 @@ lock_release( ++count; } + + lock_mutex_exit(); } /* True if a lock mode is S or X */ @@ -4736,7 +4732,7 @@ lock_trx_table_locks_find( { bool found = false; - trx_mutex_enter(trx); + ut_ad(trx_mutex_own(trx)); for (lock_list::const_iterator it = trx->lock.table_locks.begin(), end = trx->lock.table_locks.end(); it != end; ++it) { @@ -4759,8 +4755,6 @@ lock_trx_table_locks_find( ut_a(lock->un_member.tab_lock.table != NULL); } - trx_mutex_exit(trx); - return(found); } @@ -4781,25 +4775,23 @@ lock_table_queue_validate( lock != NULL; lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, lock)) { - /* Transaction state may change from ACTIVE to PREPARED. - State change to COMMITTED is not possible while we are - holding lock_sys.mutex: it is done by lock_trx_release_locks() - under lock_sys.mutex protection. - Transaction in NOT_STARTED state cannot hold locks, and - lock->trx->state can only move to NOT_STARTED from COMMITTED. */ + /* lock->trx->state cannot change from or to NOT_STARTED + while we are holding the lock_sys.mutex. It may change + from ACTIVE or PREPARED to PREPARED or COMMITTED. */ + trx_mutex_enter(lock->trx); check_trx_state(lock->trx); - if (!lock_get_wait(lock)) { - + if (lock->trx->state == TRX_STATE_COMMITTED_IN_MEMORY) { + } else if (!lock_get_wait(lock)) { ut_a(!lock_table_other_has_incompatible( lock->trx, 0, table, lock_get_mode(lock))); } else { - ut_a(lock_table_has_to_wait_in_queue(lock)); } ut_a(lock_trx_table_locks_find(lock->trx, lock)); + trx_mutex_exit(lock->trx); } return(TRUE); @@ -4846,42 +4838,41 @@ lock_rec_queue_validate( lock != NULL; lock = lock_rec_get_next_const(heap_no, lock)) { - ut_ad(!trx_is_ac_nl_ro(lock->trx)); + ut_ad(!index || lock->index == index); - if (lock_get_wait(lock)) { - ut_a(lock_rec_has_to_wait_in_queue(lock)); - } + trx_mutex_enter(lock->trx); + ut_ad(!trx_is_ac_nl_ro(lock->trx)); + ut_ad(trx_state_eq(lock->trx, + TRX_STATE_COMMITTED_IN_MEMORY) + || !lock_get_wait(lock) + || lock_rec_has_to_wait_in_queue(lock)); + trx_mutex_exit(lock->trx); + } - if (index != NULL) { - ut_a(lock->index == index); - } +func_exit: + if (!locked_lock_trx_sys) { + lock_mutex_exit(); } - goto func_exit; + return true; } ut_ad(page_rec_is_leaf(rec)); + ut_ad(lock_mutex_own()); - if (index == NULL) { - - /* Nothing we can do */ - - } else if (dict_index_is_clust(index)) { - /* Unlike the non-debug code, this invariant can only succeed - if the check and assertion are covered by the lock mutex. */ - - const trx_id_t impl_trx_id = lock_clust_rec_some_has_impl( - rec, index, offsets); - - const trx_t *impl_trx = impl_trx_id - ? trx_sys.find(current_trx(), impl_trx_id, false) - : 0; + const trx_id_t impl_trx_id = index && index->is_primary() + ? lock_clust_rec_some_has_impl(rec, index, offsets) + : 0; - ut_ad(lock_mutex_own()); - /* impl_trx cannot be committed until lock_mutex_exit() - because lock_trx_release_locks() acquires lock_sys.mutex */ + if (trx_t *impl_trx = impl_trx_id + ? trx_sys.find(current_trx(), impl_trx_id, false) + : 0) { + /* impl_trx could have been committed before we + acquire its mutex, but not thereafter. */ - if (!impl_trx) { + mutex_enter(&impl_trx->mutex); + ut_ad(impl_trx->state != TRX_STATE_NOT_STARTED); + if (impl_trx->state == TRX_STATE_COMMITTED_IN_MEMORY) { } else if (const lock_t* other_lock = lock_rec_other_has_expl_req( LOCK_S, block, true, heap_no, @@ -4923,6 +4914,8 @@ lock_rec_queue_validate( ut_ad(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, block, heap_no, impl_trx)); } + + mutex_exit(&impl_trx->mutex); } for (lock = lock_rec_get_first(lock_sys.rec_hash, block, heap_no); @@ -4967,12 +4960,7 @@ lock_rec_queue_validate( ut_ad(innodb_lock_schedule_algorithm == INNODB_LOCK_SCHEDULE_ALGORITHM_FCFS || lock_queue_validate(lock)); -func_exit: - if (!locked_lock_trx_sys) { - lock_mutex_exit(); - } - - return(TRUE); + goto func_exit; } /*********************************************************************//** @@ -5399,25 +5387,19 @@ lock_rec_convert_impl_to_expl_for_trx( ut_ad(!rec_is_metadata(rec, *index)); DEBUG_SYNC_C("before_lock_rec_convert_impl_to_expl_for_trx"); - lock_mutex_enter(); - + trx_mutex_enter(trx); ut_ad(!trx_state_eq(trx, TRX_STATE_NOT_STARTED)); if (!trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY) && !lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, block, heap_no, trx)) { - - ulint type_mode; - - type_mode = (LOCK_REC | LOCK_X | LOCK_REC_NOT_GAP); - - lock_rec_add_to_queue( - type_mode, block, heap_no, index, trx, FALSE); + lock_rec_add_to_queue(LOCK_REC | LOCK_X | LOCK_REC_NOT_GAP, + block, heap_no, index, trx, true); } lock_mutex_exit(); - + trx_mutex_exit(trx); trx->release_reference(); DEBUG_SYNC_C("after_lock_rec_convert_impl_to_expl_for_trx"); @@ -5440,13 +5422,17 @@ static my_bool lock_rec_other_trx_holds_expl_callback( mutex_enter(&element->mutex); if (element->trx) { - lock_t *expl_lock= lock_rec_has_expl(LOCK_S | LOCK_REC_NOT_GAP, arg->block, - arg->heap_no, element->trx); + trx_mutex_enter(element->trx); + ut_ad(element->trx->state != TRX_STATE_NOT_STARTED); + lock_t *expl_lock= element->trx->state == TRX_STATE_COMMITTED_IN_MEMORY + ? NULL : lock_rec_has_expl(LOCK_S | LOCK_REC_NOT_GAP, arg->block, + arg->heap_no, element->trx); /* An explicit lock is held by trx other than the trx holding the implicit lock. */ ut_ad(!expl_lock || expl_lock->trx == arg->impl_trx); + trx_mutex_exit(element->trx); } mutex_exit(&element->mutex); return 0; @@ -5476,9 +5462,6 @@ static void lock_rec_other_trx_holds_expl(trx_t *caller_trx, trx_t *trx, ut_ad(!page_rec_is_metadata(rec)); lock_mutex_enter(); ut_ad(trx->is_referenced()); - /* Prevent a data race with trx_prepare(), which could change the - state from ACTIVE to PREPARED. Other state changes should be - blocked by lock_mutex_own() and trx->is_referenced(). */ trx_mutex_enter(trx); const trx_state_t state = trx->state; trx_mutex_exit(trx); @@ -6242,92 +6225,6 @@ lock_unlock_table_autoinc( } } -/*********************************************************************//** -Releases a transaction's locks, and releases possible other transactions -waiting because of these locks. Change the state of the transaction to -TRX_STATE_COMMITTED_IN_MEMORY. */ -void -lock_trx_release_locks( -/*===================*/ - trx_t* trx) /*!< in/out: transaction */ -{ - check_trx_state(trx); - ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED) - || trx_state_eq(trx, TRX_STATE_PREPARED_RECOVERED) - || trx_state_eq(trx, TRX_STATE_ACTIVE)); - - bool release_lock = UT_LIST_GET_LEN(trx->lock.trx_locks) > 0; - - /* Don't take lock_sys.mutex if trx didn't acquire any lock. */ - if (release_lock) { - - /* The transition of trx->state to TRX_STATE_COMMITTED_IN_MEMORY - is protected by both the lock_sys.mutex and the trx->mutex. */ - lock_mutex_enter(); - } - - /* The following assignment makes the transaction committed in memory - and makes its changes to data visible to other transactions. - NOTE that there is a small discrepancy from the strict formal - visibility rules here: a human user of the database can see - modifications made by another transaction T even before the necessary - log segment has been flushed to the disk. If the database happens to - crash before the flush, the user has seen modifications from T which - will never be a committed transaction. However, any transaction T2 - which sees the modifications of the committing transaction T, and - which also itself makes modifications to the database, will get an lsn - larger than the committing transaction T. In the case where the log - flush fails, and T never gets committed, also T2 will never get - committed. */ - - /*--------------------------------------*/ - trx_mutex_enter(trx); - trx->state = TRX_STATE_COMMITTED_IN_MEMORY; - trx_mutex_exit(trx); - /*--------------------------------------*/ - - if (trx->is_referenced()) { - - ut_a(release_lock); - - lock_mutex_exit(); - - while (trx->is_referenced()) { - - DEBUG_SYNC_C("waiting_trx_is_not_referenced"); - - /** Doing an implicit to explicit conversion - should not be expensive. */ - ut_delay(srv_spin_wait_delay); - } - - lock_mutex_enter(); - } - - ut_ad(!trx->is_referenced()); - - if (release_lock) { - - lock_release(trx); - - lock_mutex_exit(); - } - - trx->lock.n_rec_locks = 0; - - /* We don't remove the locks one by one from the vector for - efficiency reasons. We simply reset it because we would have - released all the locks anyway. */ - - trx->lock.table_locks.clear(); - - ut_a(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0); - ut_a(ib_vector_is_empty(trx->autoinc_locks)); - ut_a(trx->lock.table_locks.empty()); - - mem_heap_empty(trx->lock.lock_heap); -} - static inline dberr_t lock_trx_handle_wait_low(trx_t* trx) { ut_ad(lock_mutex_own()); @@ -6403,21 +6300,26 @@ static my_bool lock_table_locks_lookup(rw_trx_hash_element_t *element, mutex_enter(&element->mutex); if (element->trx) { + trx_mutex_enter(element->trx); check_trx_state(element->trx); - for (const lock_t *lock= UT_LIST_GET_FIRST(element->trx->lock.trx_locks); - lock != NULL; - lock= UT_LIST_GET_NEXT(trx_locks, lock)) + if (element->trx->state != TRX_STATE_COMMITTED_IN_MEMORY) { - ut_ad(lock->trx == element->trx); - if (lock_get_type_low(lock) == LOCK_REC) + for (const lock_t *lock= UT_LIST_GET_FIRST(element->trx->lock.trx_locks); + lock != NULL; + lock= UT_LIST_GET_NEXT(trx_locks, lock)) { - ut_ad(!dict_index_is_online_ddl(lock->index) || - dict_index_is_clust(lock->index)); - ut_ad(lock->index->table != table); + ut_ad(lock->trx == element->trx); + if (lock_get_type_low(lock) == LOCK_REC) + { + ut_ad(!dict_index_is_online_ddl(lock->index) || + lock->index->is_primary()); + ut_ad(lock->index->table != table); + } + else + ut_ad(lock->un_member.tab_lock.table != table); } - else - ut_ad(lock->un_member.tab_lock.table != table); } + trx_mutex_exit(element->trx); } mutex_exit(&element->mutex); return 0; @@ -6585,7 +6487,7 @@ DeadlockChecker::start_print() if (srv_print_all_deadlocks) { ib::info() << "Transactions deadlock detected, dumping" - << " detailed information."; + " detailed information."; } } |