From 53f7a1a6a92772a333704dde2cbd1fa0fd958066 Mon Sep 17 00:00:00 2001 From: marko Date: Wed, 13 Jan 2010 20:38:53 +0000 Subject: [PATCH] branches/zip: lock_rec_validate_page(): Only validate the record queues when the thread is not holding a space->latch. When UNIV_DEBUG is defined while UNIV_SYNC_DEBUG is not, latching order violations will still occur and deadlocks will be possible. sync_thread_levels_nonempty_gen(): Renamed from sync_thread_levels_empty_gen(). Return the violating latch or NULL instead of FALSE or TRUE, except that there will be a ut_error before the non-NULL return. sync_thread_levels_empty_gen(): A macro that negates the return value of sync_thread_levels_nonempty_gen(). sync_thread_levels_contains(): New function, based on sync_thread_levels_nonempty_gen(). This should fix Issue #441. --- include/sync0sync.h | 21 ++++++++++---- lock/lock0lock.c | 7 +++++ sync/sync0sync.c | 68 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 82 insertions(+), 14 deletions(-) diff --git a/include/sync0sync.h b/include/sync0sync.h index df990823cc4..f8d86eb1c84 100644 --- a/include/sync0sync.h +++ b/include/sync0sync.h @@ -238,16 +238,27 @@ ibool sync_thread_levels_empty(void); /*==========================*/ /******************************************************************//** -Checks that the level array for the current thread is empty. -@return TRUE if empty except the exceptions specified below */ +Checks if the level array for the current thread contains a +mutex or rw-latch at the specified level. +@return a matching latch, or NULL if not found */ UNIV_INTERN -ibool -sync_thread_levels_empty_gen( -/*=========================*/ +void* +sync_thread_levels_contains( +/*========================*/ + ulint level); /*!< in: latching order level + (SYNC_DICT, ...)*/ +/******************************************************************//** +Checks if the level array for the current thread is empty. +@return a latch, or NULL if empty except the exceptions specified below */ +UNIV_INTERN +void* +sync_thread_levels_nonempty_gen( +/*============================*/ ibool dict_mutex_allowed); /*!< in: TRUE if dictionary mutex is allowed to be owned by the thread, also purge_is_running mutex is allowed */ +#define sync_thread_levels_empty_gen(d) (!sync_thread_levels_nonempty_gen(d)) /******************************************************************//** Gets the debug information for a reserved mutex. */ UNIV_INTERN diff --git a/lock/lock0lock.c b/lock/lock0lock.c index 3db7c2b36bc..0fa67d31716 100644 --- a/lock/lock0lock.c +++ b/lock/lock0lock.c @@ -4766,6 +4766,13 @@ loop: || lock->trx->conc_state == TRX_PREPARED || lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY); +# ifdef UNIV_SYNC_DEBUG + /* Only validate the record queues when this thread is not + holding a space->latch. Deadlocks are possible due to + latching order violation when UNIV_DEBUG is defined while + UNIV_SYNC_DEBUG is not. */ + if (!sync_thread_levels_contains(SYNC_FSP)) +# endif /* UNIV_SYNC_DEBUG */ for (i = nth_bit; i < lock_rec_get_n_bits(lock); i++) { if (i == 1 || lock_rec_get_nth_bit(lock, i)) { diff --git a/sync/sync0sync.c b/sync/sync0sync.c index f1527907ef6..669e0667485 100644 --- a/sync/sync0sync.c +++ b/sync/sync0sync.c @@ -958,12 +958,62 @@ sync_thread_levels_contain( } /******************************************************************//** -Checks that the level array for the current thread is empty. -@return TRUE if empty except the exceptions specified below */ +Checks if the level array for the current thread contains a +mutex or rw-latch at the specified level. +@return a matching latch, or NULL if not found */ UNIV_INTERN -ibool -sync_thread_levels_empty_gen( -/*=========================*/ +void* +sync_thread_levels_contains( +/*========================*/ + ulint level) /*!< in: latching order level + (SYNC_DICT, ...)*/ +{ + sync_level_t* arr; + sync_thread_t* thread_slot; + sync_level_t* slot; + ulint i; + + if (!sync_order_checks_on) { + + return(NULL); + } + + mutex_enter(&sync_thread_mutex); + + thread_slot = sync_thread_level_arrays_find_slot(); + + if (thread_slot == NULL) { + + mutex_exit(&sync_thread_mutex); + + return(NULL); + } + + arr = thread_slot->levels; + + for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + + slot = sync_thread_levels_get_nth(arr, i); + + if (slot->latch != NULL && slot->level == level) { + + mutex_exit(&sync_thread_mutex); + return(slot->latch); + } + } + + mutex_exit(&sync_thread_mutex); + + return(NULL); +} + +/******************************************************************//** +Checks that the level array for the current thread is empty. +@return a latch, or NULL if empty except the exceptions specified below */ +UNIV_INTERN +void* +sync_thread_levels_nonempty_gen( +/*============================*/ ibool dict_mutex_allowed) /*!< in: TRUE if dictionary mutex is allowed to be owned by the thread, also purge_is_running mutex is @@ -976,7 +1026,7 @@ sync_thread_levels_empty_gen( if (!sync_order_checks_on) { - return(TRUE); + return(NULL); } mutex_enter(&sync_thread_mutex); @@ -987,7 +1037,7 @@ sync_thread_levels_empty_gen( mutex_exit(&sync_thread_mutex); - return(TRUE); + return(NULL); } arr = thread_slot->levels; @@ -1004,13 +1054,13 @@ sync_thread_levels_empty_gen( mutex_exit(&sync_thread_mutex); ut_error; - return(FALSE); + return(slot->latch); } } mutex_exit(&sync_thread_mutex); - return(TRUE); + return(NULL); } /******************************************************************//**