diff options
Diffstat (limited to 'storage/innobase/sync')
-rw-r--r-- | storage/innobase/sync/sync0arr.c | 73 | ||||
-rw-r--r-- | storage/innobase/sync/sync0rw.c | 35 | ||||
-rw-r--r-- | storage/innobase/sync/sync0sync.c | 450 |
3 files changed, 346 insertions, 212 deletions
diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c index 753ebd958ac..30caddccced 100644 --- a/storage/innobase/sync/sync0arr.c +++ b/storage/innobase/sync/sync0arr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -40,6 +40,7 @@ Created 9/5/1995 Heikki Tuuri #include "os0sync.h" #include "os0file.h" #include "srv0srv.h" +#include "ha_prototypes.h" /* WAIT ARRAY @@ -478,8 +479,8 @@ sync_array_cell_print( fprintf(file, "--Thread %lu has waited at %s line %lu" " for %.2f seconds the semaphore:\n", - (ulong) os_thread_pf(cell->thread), cell->file, - (ulong) cell->line, + (ulong) os_thread_pf(cell->thread), + innobase_basename(cell->file), (ulong) cell->line, difftime(time(NULL), cell->reservation_time)); if (type == SYNC_MUTEX) { @@ -493,7 +494,8 @@ sync_array_cell_print( "Last time reserved in file %s line %lu, " #endif /* UNIV_SYNC_DEBUG */ "waiters flag %lu\n", - (void*) mutex, mutex->cfile_name, (ulong) mutex->cline, + (void*) mutex, innobase_basename(mutex->cfile_name), + (ulong) mutex->cline, (ulong) mutex->lock_word, #ifdef UNIV_SYNC_DEBUG mutex->file_name, (ulong) mutex->line, @@ -512,7 +514,7 @@ sync_array_cell_print( fprintf(file, " RW-latch at %p created in file %s line %lu\n", - (void*) rwlock, rwlock->cfile_name, + (void*) rwlock, innobase_basename(rwlock->cfile_name), (ulong) rwlock->cline); writer = rw_lock_get_writer(rwlock); if (writer != RW_LOCK_NOT_LOCKED) { @@ -533,7 +535,7 @@ sync_array_cell_print( (ulong) rw_lock_get_reader_count(rwlock), (ulong) rwlock->waiters, rwlock->lock_word, - rwlock->last_s_file_name, + innobase_basename(rwlock->last_s_file_name), (ulong) rwlock->last_s_line, rwlock->last_x_file_name, (ulong) rwlock->last_x_line); @@ -590,9 +592,6 @@ sync_array_deadlock_step( ulint depth) /*!< in: recursion depth */ { sync_cell_t* new; - ibool ret; - - depth++; if (pass != 0) { /* If pass != 0, then we do not know which threads are @@ -604,7 +603,7 @@ sync_array_deadlock_step( new = sync_array_find_thread(arr, thread); - if (new == start) { + if (UNIV_UNLIKELY(new == start)) { /* Stop running of other threads */ ut_dbg_stop_threads = TRUE; @@ -616,11 +615,7 @@ sync_array_deadlock_step( return(TRUE); } else if (new) { - ret = sync_array_detect_deadlock(arr, start, new, depth); - - if (ret) { - return(TRUE); - } + return(sync_array_detect_deadlock(arr, start, new, depth + 1)); } return(FALSE); } @@ -721,7 +716,7 @@ print: fprintf(stderr, "rw-lock %p ", (void*) lock); sync_array_cell_print(stderr, cell); - rw_lock_debug_print(debug); + rw_lock_debug_print(stderr, debug); return(TRUE); } } @@ -920,8 +915,10 @@ Prints warnings of long semaphore waits to stderr. @return TRUE if fatal semaphore wait threshold was exceeded */ UNIV_INTERN ibool -sync_array_print_long_waits(void) -/*=============================*/ +sync_array_print_long_waits( +/*========================*/ + os_thread_id_t* waiter, /*!< out: longest waiting thread */ + const void** sema) /*!< out: longest-waited-for semaphore */ { sync_cell_t* cell; ibool old_val; @@ -929,24 +926,52 @@ sync_array_print_long_waits(void) ulint i; ulint fatal_timeout = srv_fatal_semaphore_wait_threshold; ibool fatal = FALSE; + double longest_diff = 0; + +#ifdef UNIV_DEBUG_VALGRIND + /* Increase the timeouts if running under valgrind because it executes + extremely slowly. UNIV_DEBUG_VALGRIND does not necessary mean that + we are running under valgrind but we have no better way to tell. + See Bug#58432 innodb.innodb_bug56143 fails under valgrind + for an example */ +# define SYNC_ARRAY_TIMEOUT 2400 + fatal_timeout *= 10; +#else +# define SYNC_ARRAY_TIMEOUT 240 +#endif for (i = 0; i < sync_primary_wait_array->n_cells; i++) { + double diff; + void* wait_object; + cell = sync_array_get_nth_cell(sync_primary_wait_array, i); - if (cell->wait_object != NULL && cell->waiting - && difftime(time(NULL), cell->reservation_time) > 240) { + wait_object = cell->wait_object; + + if (wait_object == NULL || !cell->waiting) { + + continue; + } + + diff = difftime(time(NULL), cell->reservation_time); + + if (diff > SYNC_ARRAY_TIMEOUT) { fputs("InnoDB: Warning: a long semaphore wait:\n", stderr); sync_array_cell_print(stderr, cell); noticed = TRUE; } - if (cell->wait_object != NULL && cell->waiting - && difftime(time(NULL), cell->reservation_time) - > fatal_timeout) { + if (diff > fatal_timeout) { fatal = TRUE; } + + if (diff > longest_diff) { + longest_diff = diff; + *sema = wait_object; + *waiter = cell->thread; + } } if (noticed) { @@ -977,6 +1002,8 @@ sync_array_print_long_waits(void) " to the standard error stream\n"); } +#undef SYNC_ARRAY_TIMEOUT + return(fatal); } diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index 4dbaaa97bd9..397d505df50 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -39,6 +39,7 @@ Created 9/11/1995 Heikki Tuuri #include "mem0mem.h" #include "srv0srv.h" #include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ +#include "ha_prototypes.h" /* IMPLEMENTATION OF THE RW_LOCK @@ -271,6 +272,9 @@ rw_lock_create_func( contains garbage at initialization and cannot be used for recursive x-locking. */ lock->recursive = FALSE; + /* Silence Valgrind when UNIV_DEBUG_VALGRIND is not enabled. */ + memset((void*) &lock->writer_thread, 0, sizeof lock->writer_thread); + UNIV_MEM_INVALID(&lock->writer_thread, sizeof lock->writer_thread); #ifdef UNIV_SYNC_DEBUG UT_LIST_INIT(lock->debug_list); @@ -404,7 +408,8 @@ lock_loop: " cfile %s cline %lu rnds %lu\n", (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) lock, - lock->cfile_name, (ulong) lock->cline, (ulong) i); + innobase_basename(lock->cfile_name), + (ulong) lock->cline, (ulong) i); } /* We try once again to obtain the lock */ @@ -439,7 +444,8 @@ lock_loop: "Thread %lu OS wait rw-s-lock at %p" " cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), - (void*) lock, lock->cfile_name, + (void*) lock, + innobase_basename(lock->cfile_name), (ulong) lock->cline); } @@ -661,7 +667,8 @@ lock_loop: "Thread %lu spin wait rw-x-lock at %p" " cfile %s cline %lu rnds %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, - lock->cfile_name, (ulong) lock->cline, (ulong) i); + innobase_basename(lock->cfile_name), + (ulong) lock->cline, (ulong) i); } sync_array_reserve_cell(sync_primary_wait_array, @@ -684,7 +691,8 @@ lock_loop: "Thread %lu OS wait for rw-x-lock at %p" " cfile %s cline %lu\n", os_thread_pf(os_thread_get_curr_id()), (void*) lock, - lock->cfile_name, (ulong) lock->cline); + innobase_basename(lock->cfile_name), + (ulong) lock->cline); } /* these stats may not be accurate */ @@ -936,7 +944,7 @@ rw_lock_list_print_info( info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { - rw_lock_debug_print(info); + rw_lock_debug_print(file, info); info = UT_LIST_GET_NEXT(list, info); } } @@ -984,7 +992,7 @@ rw_lock_print( info = UT_LIST_GET_FIRST(lock->debug_list); while (info != NULL) { - rw_lock_debug_print(info); + rw_lock_debug_print(stderr, info); info = UT_LIST_GET_NEXT(list, info); } } @@ -996,28 +1004,29 @@ UNIV_INTERN void rw_lock_debug_print( /*================*/ + FILE* f, /*!< in: output stream */ rw_lock_debug_t* info) /*!< in: debug struct */ { ulint rwt; rwt = info->lock_type; - fprintf(stderr, "Locked: thread %ld file %s line %ld ", + fprintf(f, "Locked: thread %lu file %s line %lu ", (ulong) os_thread_pf(info->thread_id), info->file_name, (ulong) info->line); if (rwt == RW_LOCK_SHARED) { - fputs("S-LOCK", stderr); + fputs("S-LOCK", f); } else if (rwt == RW_LOCK_EX) { - fputs("X-LOCK", stderr); + fputs("X-LOCK", f); } else if (rwt == RW_LOCK_WAIT_EX) { - fputs("WAIT X-LOCK", stderr); + fputs("WAIT X-LOCK", f); } else { ut_error; } if (info->pass != 0) { - fprintf(stderr, " pass value %lu", (ulong) info->pass); + fprintf(f, " pass value %lu", (ulong) info->pass); } - putc('\n', stderr); + putc('\n', f); } /***************************************************************//** diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 8062d9e902e..0b56e736209 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2011, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -43,6 +43,7 @@ Created 9/5/1995 Heikki Tuuri #ifdef UNIV_SYNC_DEBUG # include "srv0start.h" /* srv_is_being_started */ #endif /* UNIV_SYNC_DEBUG */ +#include "ha_prototypes.h" /* REASONS FOR IMPLEMENTING THE SPIN LOCK MUTEX @@ -188,12 +189,12 @@ UNIV_INTERN sync_array_t* sync_primary_wait_array; /** This variable is set to TRUE when sync_init is called */ UNIV_INTERN ibool sync_initialized = FALSE; +#ifdef UNIV_SYNC_DEBUG /** An acquired mutex or rw-lock and its level in the latching order */ typedef struct sync_level_struct sync_level_t; /** Mutexes or rw-locks held by a thread */ typedef struct sync_thread_struct sync_thread_t; -#ifdef UNIV_SYNC_DEBUG /** The latch levels currently owned by threads are stored in this data structure; the size of this array is OS_THREAD_MAX_N */ @@ -220,24 +221,43 @@ UNIV_INTERN mysql_pfs_key_t mutex_list_mutex_key; #ifdef UNIV_SYNC_DEBUG /** Latching order checks start when this is set TRUE */ UNIV_INTERN ibool sync_order_checks_on = FALSE; -#endif /* UNIV_SYNC_DEBUG */ + +/** Number of slots reserved for each OS thread in the sync level array */ +static const ulint SYNC_THREAD_N_LEVELS = 10000; + +typedef struct sync_arr_struct sync_arr_t; + +/** Array for tracking sync levels per thread. */ +struct sync_arr_struct { + ulint in_use; /*!< Number of active cells */ + ulint n_elems; /*!< Number of elements in the array */ + ulint max_elems; /*!< Maximum elements */ + ulint next_free; /*!< ULINT_UNDEFINED or index of next + free slot */ + sync_level_t* elems; /*!< Array elements */ +}; /** Mutexes or rw-locks held by a thread */ struct sync_thread_struct{ - os_thread_id_t id; /*!< OS thread id */ - sync_level_t* levels; /*!< level array for this thread; if - this is NULL this slot is unused */ + os_thread_id_t id; /*!< OS thread id */ + sync_arr_t* levels; /*!< level array for this thread; if + this is NULL this slot is unused */ }; -/** Number of slots reserved for each OS thread in the sync level array */ -#define SYNC_THREAD_N_LEVELS 10000 - /** An acquired mutex or rw-lock and its level in the latching order */ struct sync_level_struct{ - void* latch; /*!< pointer to a mutex or an rw-lock; NULL means that - the slot is empty */ - ulint level; /*!< level of the latch in the latching order */ + void* latch; /*!< pointer to a mutex or an + rw-lock; NULL means that + the slot is empty */ + ulint level; /*!< level of the latch in the + latching order. This field is + overloaded to serve as a node in a + linked list of free nodes too. When + latch == NULL then this will contain + the ordinal value of the next free + element */ }; +#endif /* UNIV_SYNC_DEBUG */ /******************************************************************//** Creates, or rather, initializes a mutex object in a specified memory @@ -524,7 +544,8 @@ spin_loop: "Thread %lu spin wait mutex at %p" " cfile %s cline %lu rnds %lu\n", (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex, - mutex->cfile_name, (ulong) mutex->cline, (ulong) i); + innobase_basename(mutex->cfile_name), + (ulong) mutex->cline, (ulong) i); #endif mutex_spin_round_count += i; @@ -601,7 +622,8 @@ spin_loop: fprintf(stderr, "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n", (ulong) os_thread_pf(os_thread_get_curr_id()), (void*) mutex, - mutex->cfile_name, (ulong) mutex->cline, (ulong) i); + innobase_basename(mutex->cfile_name), + (ulong) mutex->cline, (ulong) i); #endif mutex_os_wait_count++; @@ -745,27 +767,28 @@ mutex_n_reserved(void) /*==================*/ { mutex_t* mutex; - ulint count = 0; + ulint count = 0; mutex_enter(&mutex_list_mutex); - mutex = UT_LIST_GET_FIRST(mutex_list); + for (mutex = UT_LIST_GET_FIRST(mutex_list); + mutex != NULL; + mutex = UT_LIST_GET_NEXT(list, mutex)) { - while (mutex != NULL) { if (mutex_get_lock_word(mutex) != 0) { count++; } - - mutex = UT_LIST_GET_NEXT(list, mutex); } mutex_exit(&mutex_list_mutex); ut_a(count >= 1); - return(count - 1); /* Subtract one, because this function itself - was holding one mutex (mutex_list_mutex) */ + /* Subtract one, because this function itself was holding + one mutex (mutex_list_mutex) */ + + return(count - 1); } /******************************************************************//** @@ -781,20 +804,6 @@ sync_all_freed(void) } /******************************************************************//** -Gets the value in the nth slot in the thread level arrays. -@return pointer to thread slot */ -static -sync_thread_t* -sync_thread_level_arrays_get_nth( -/*=============================*/ - ulint n) /*!< in: slot number */ -{ - ut_ad(n < OS_THREAD_MAX_N); - - return(sync_thread_level_arrays + n); -} - -/******************************************************************//** Looks for the thread slot for the calling thread. @return pointer to thread slot, NULL if not found */ static @@ -803,15 +812,15 @@ sync_thread_level_arrays_find_slot(void) /*====================================*/ { - sync_thread_t* slot; - os_thread_id_t id; ulint i; + os_thread_id_t id; id = os_thread_get_curr_id(); for (i = 0; i < OS_THREAD_MAX_N; i++) { + sync_thread_t* slot; - slot = sync_thread_level_arrays_get_nth(i); + slot = &sync_thread_level_arrays[i]; if (slot->levels && os_thread_eq(slot->id, id)) { @@ -831,12 +840,12 @@ sync_thread_level_arrays_find_free(void) /*====================================*/ { - sync_thread_t* slot; ulint i; for (i = 0; i < OS_THREAD_MAX_N; i++) { + sync_thread_t* slot; - slot = sync_thread_level_arrays_get_nth(i); + slot = &sync_thread_level_arrays[i]; if (slot->levels == NULL) { @@ -848,19 +857,45 @@ sync_thread_level_arrays_find_free(void) } /******************************************************************//** -Gets the value in the nth slot in the thread level array. -@return pointer to level slot */ +Print warning. */ static -sync_level_t* -sync_thread_levels_get_nth( -/*=======================*/ - sync_level_t* arr, /*!< in: pointer to level array for an OS - thread */ - ulint n) /*!< in: slot number */ +void +sync_print_warning( +/*===============*/ + const sync_level_t* slot) /*!< in: slot for which to + print warning */ { - ut_ad(n < SYNC_THREAD_N_LEVELS); + mutex_t* mutex; + + mutex = slot->latch; - return(arr + n); + if (mutex->magic_n == MUTEX_MAGIC_N) { + fprintf(stderr, + "Mutex created at %s %lu\n", + innobase_basename(mutex->cfile_name), + (ulong) mutex->cline); + + if (mutex_get_lock_word(mutex) != 0) { + ulint line; + const char* file_name; + os_thread_id_t thread_id; + + mutex_get_debug_info( + mutex, &file_name, &line, &thread_id); + + fprintf(stderr, + "InnoDB: Locked mutex:" + " addr %p thread %ld file %s line %ld\n", + (void*) mutex, os_thread_pf(thread_id), + file_name, (ulong) line); + } else { + fputs("Not locked\n", stderr); + } + } else { + rw_lock_t* lock = slot->latch; + + rw_lock_print(lock); + } } /******************************************************************//** @@ -871,69 +906,29 @@ static ibool sync_thread_levels_g( /*=================*/ - sync_level_t* arr, /*!< in: pointer to level array for an OS + sync_arr_t* arr, /*!< in: pointer to level array for an OS thread */ ulint limit, /*!< in: level limit */ ulint warn) /*!< in: TRUE=display a diagnostic message */ { - sync_level_t* slot; - rw_lock_t* lock; - mutex_t* mutex; ulint i; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { - - slot = sync_thread_levels_get_nth(arr, i); - - if (slot->latch != NULL) { - if (slot->level <= limit) { - - if (!warn) { + for (i = 0; i < arr->n_elems; i++) { + const sync_level_t* slot; - return(FALSE); - } - - lock = slot->latch; - mutex = slot->latch; + slot = &arr->elems[i]; + if (slot->latch != NULL && slot->level <= limit) { + if (warn) { fprintf(stderr, "InnoDB: sync levels should be" " > %lu but a level is %lu\n", (ulong) limit, (ulong) slot->level); - if (mutex->magic_n == MUTEX_MAGIC_N) { - fprintf(stderr, - "Mutex created at %s %lu\n", - mutex->cfile_name, - (ulong) mutex->cline); - - if (mutex_get_lock_word(mutex) != 0) { - const char* file_name; - ulint line; - os_thread_id_t thread_id; - - mutex_get_debug_info( - mutex, &file_name, - &line, &thread_id); - - fprintf(stderr, - "InnoDB: Locked mutex:" - " addr %p thread %ld" - " file %s line %ld\n", - (void*) mutex, - os_thread_pf( - thread_id), - file_name, - (ulong) line); - } else { - fputs("Not locked\n", stderr); - } - } else { - rw_lock_print(lock); - } - - return(FALSE); + sync_print_warning(slot); } + + return(FALSE); } } @@ -942,31 +937,29 @@ sync_thread_levels_g( /******************************************************************//** Checks if the level value is stored in the level array. -@return TRUE if stored */ +@return slot if found or NULL */ static -ibool +const sync_level_t* sync_thread_levels_contain( /*=======================*/ - sync_level_t* arr, /*!< in: pointer to level array for an OS + sync_arr_t* arr, /*!< in: pointer to level array for an OS thread */ ulint level) /*!< in: level */ { - sync_level_t* slot; ulint i; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + for (i = 0; i < arr->n_elems; i++) { + const sync_level_t* slot; - slot = sync_thread_levels_get_nth(arr, i); + slot = &arr->elems[i]; - if (slot->latch != NULL) { - if (slot->level == level) { + if (slot->latch != NULL && slot->level == level) { - return(TRUE); - } + return(slot); } } - return(FALSE); + return(NULL); } /******************************************************************//** @@ -980,10 +973,9 @@ 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; + sync_arr_t* arr; + sync_thread_t* thread_slot; if (!sync_order_checks_on) { @@ -1003,9 +995,10 @@ sync_thread_levels_contains( arr = thread_slot->levels; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + for (i = 0; i < arr->n_elems; i++) { + sync_level_t* slot; - slot = sync_thread_levels_get_nth(arr, i); + slot = &arr->elems[i]; if (slot->latch != NULL && slot->level == level) { @@ -1027,14 +1020,11 @@ 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 */ + allowed to be owned by the thread */ { - sync_level_t* arr; - sync_thread_t* thread_slot; - sync_level_t* slot; ulint i; + sync_arr_t* arr; + sync_thread_t* thread_slot; if (!sync_order_checks_on) { @@ -1054,9 +1044,10 @@ sync_thread_levels_nonempty_gen( arr = thread_slot->levels; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + for (i = 0; i < arr->n_elems; ++i) { + const sync_level_t* slot; - slot = sync_thread_levels_get_nth(arr, i); + slot = &arr->elems[i]; if (slot->latch != NULL && (!dict_mutex_allowed @@ -1076,14 +1067,61 @@ sync_thread_levels_nonempty_gen( } /******************************************************************//** -Checks that the level array for the current thread is empty. -@return TRUE if empty */ +Checks if the level array for the current thread is empty, +except for the btr_search_latch. +@return a latch, or NULL if empty except the exceptions specified below */ UNIV_INTERN -ibool -sync_thread_levels_empty(void) -/*==========================*/ +void* +sync_thread_levels_nonempty_trx( +/*============================*/ + ibool has_search_latch) + /*!< in: TRUE if and only if the thread + is supposed to hold btr_search_latch */ { - return(sync_thread_levels_empty_gen(FALSE)); + ulint i; + sync_arr_t* arr; + sync_thread_t* thread_slot; + + if (!sync_order_checks_on) { + + return(NULL); + } + + ut_a(!has_search_latch + || sync_thread_levels_contains(SYNC_SEARCH_SYS)); + + 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 < arr->n_elems; ++i) { + const sync_level_t* slot; + + slot = &arr->elems[i]; + + if (slot->latch != NULL + && (!has_search_latch + || slot->level != SYNC_SEARCH_SYS)) { + + mutex_exit(&sync_thread_mutex); + ut_error; + + return(slot->latch); + } + } + + mutex_exit(&sync_thread_mutex); + + return(NULL); } /******************************************************************//** @@ -1098,10 +1136,10 @@ sync_thread_add_level( ulint level) /*!< in: level in the latching order; if SYNC_LEVEL_VARYING, nothing is done */ { - sync_level_t* array; + ulint i; sync_level_t* slot; + sync_arr_t* array; sync_thread_t* thread_slot; - ulint i; if (!sync_order_checks_on) { @@ -1126,20 +1164,23 @@ sync_thread_add_level( thread_slot = sync_thread_level_arrays_find_slot(); if (thread_slot == NULL) { - /* We have to allocate the level array for a new thread */ - array = ut_malloc(sizeof(sync_level_t) * SYNC_THREAD_N_LEVELS); + ulint sz; - thread_slot = sync_thread_level_arrays_find_free(); + sz = sizeof(*array) + + (sizeof(*array->elems) * SYNC_THREAD_N_LEVELS); - thread_slot->id = os_thread_get_curr_id(); - thread_slot->levels = array; + /* We have to allocate the level array for a new thread */ + array = calloc(sz, sizeof(char)); + ut_a(array != NULL); - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + array->next_free = ULINT_UNDEFINED; + array->max_elems = SYNC_THREAD_N_LEVELS; + array->elems = (sync_level_t*) &array[1]; - slot = sync_thread_levels_get_nth(array, i); + thread_slot = sync_thread_level_arrays_find_free(); - slot->latch = NULL; - } + thread_slot->levels = array; + thread_slot->id = os_thread_get_curr_id(); } array = thread_slot->levels; @@ -1180,7 +1221,7 @@ sync_thread_add_level( case SYNC_RSEG: case SYNC_TRX_UNDO: case SYNC_PURGE_LATCH: - case SYNC_PURGE_SYS: + case SYNC_PURGE_QUEUE: case SYNC_DICT_AUTOINC_MUTEX: case SYNC_DICT_OPERATION: case SYNC_DICT_HEADER: @@ -1207,8 +1248,8 @@ sync_thread_add_level( case SYNC_BUF_BLOCK: /* Either the thread must own the buffer pool mutex - (buf_pool_mutex), or it is allowed to latch only ONE - buffer block (block->mutex or buf_pool_zip_mutex). */ + (buf_pool->mutex), or it is allowed to latch only ONE + buffer block (block->mutex or buf_pool->zip_mutex). */ if (!sync_thread_levels_g(array, level, FALSE)) { ut_a(sync_thread_levels_g(array, level - 1, TRUE)); ut_a(sync_thread_levels_contain(array, SYNC_BUF_POOL)); @@ -1247,10 +1288,16 @@ sync_thread_add_level( || sync_thread_levels_g(array, SYNC_FSP, TRUE)); break; case SYNC_TRX_UNDO_PAGE: + /* Purge is allowed to read in as many UNDO pages as it likes, + there was a bogus rule here earlier that forced the caller to + acquire the purge_sys_t::mutex. The purge mutex did not really + protect anything because it was only ever acquired by the + single purge thread. The purge thread can read the UNDO pages + without any covering mutex. */ + ut_a(sync_thread_levels_contain(array, SYNC_TRX_UNDO) || sync_thread_levels_contain(array, SYNC_RSEG) - || sync_thread_levels_contain(array, SYNC_PURGE_SYS) - || sync_thread_levels_g(array, SYNC_TRX_UNDO_PAGE, TRUE)); + || sync_thread_levels_g(array, level - 1, TRUE)); break; case SYNC_RSEG_HEADER: ut_a(sync_thread_levels_contain(array, SYNC_RSEG)); @@ -1303,19 +1350,26 @@ sync_thread_add_level( ut_error; } - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + if (array->next_free == ULINT_UNDEFINED) { + ut_a(array->n_elems < array->max_elems); - slot = sync_thread_levels_get_nth(array, i); + i = array->n_elems++; + } else { + i = array->next_free; + array->next_free = array->elems[i].level; + } - if (slot->latch == NULL) { - slot->latch = latch; - slot->level = level; + ut_a(i < array->n_elems); + ut_a(i != ULINT_UNDEFINED); - break; - } - } + ++array->in_use; + + slot = &array->elems[i]; - ut_a(i < SYNC_THREAD_N_LEVELS); + ut_a(slot->latch == NULL); + + slot->latch = latch; + slot->level = level; mutex_exit(&sync_thread_mutex); } @@ -1331,8 +1385,7 @@ sync_thread_reset_level( /*====================*/ void* latch) /*!< in: pointer to a mutex or an rw-lock */ { - sync_level_t* array; - sync_level_t* slot; + sync_arr_t* array; sync_thread_t* thread_slot; ulint i; @@ -1363,17 +1416,37 @@ sync_thread_reset_level( array = thread_slot->levels; - for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + for (i = 0; i < array->n_elems; i++) { + sync_level_t* slot; - slot = sync_thread_levels_get_nth(array, i); + slot = &array->elems[i]; - if (slot->latch == latch) { - slot->latch = NULL; + if (slot->latch != latch) { + continue; + } - mutex_exit(&sync_thread_mutex); + slot->latch = NULL; - return(TRUE); + /* Update the free slot list. See comment in sync_level_t + for the level field. */ + slot->level = array->next_free; + array->next_free = i; + + ut_a(array->in_use >= 1); + --array->in_use; + + /* If all cells are idle then reset the free + list. The assumption is that this will save + time when we need to scan up to n_elems. */ + + if (array->in_use == 0) { + array->n_elems = 0; + array->next_free = ULINT_UNDEFINED; } + + mutex_exit(&sync_thread_mutex); + + return(TRUE); } if (((mutex_t*) latch)->magic_n != MUTEX_MAGIC_N) { @@ -1403,11 +1476,6 @@ void sync_init(void) /*===========*/ { -#ifdef UNIV_SYNC_DEBUG - sync_thread_t* thread_slot; - ulint i; -#endif /* UNIV_SYNC_DEBUG */ - ut_a(sync_initialized == FALSE); sync_initialized = TRUE; @@ -1421,13 +1489,10 @@ sync_init(void) /* Create the thread latch level array where the latch levels are stored for each OS thread */ - sync_thread_level_arrays = ut_malloc(OS_THREAD_MAX_N - * sizeof(sync_thread_t)); - for (i = 0; i < OS_THREAD_MAX_N; i++) { + sync_thread_level_arrays = calloc( + sizeof(sync_thread_t), OS_THREAD_MAX_N); + ut_a(sync_thread_level_arrays != NULL); - thread_slot = sync_thread_level_arrays_get_nth(i); - thread_slot->levels = NULL; - } #endif /* UNIV_SYNC_DEBUG */ /* Init the mutex list and create the mutex to protect it. */ @@ -1454,6 +1519,34 @@ sync_init(void) #endif /* UNIV_SYNC_DEBUG */ } +#ifdef UNIV_SYNC_DEBUG +/******************************************************************//** +Frees all debug memory. */ +static +void +sync_thread_level_arrays_free(void) +/*===============================*/ + +{ + ulint i; + + for (i = 0; i < OS_THREAD_MAX_N; i++) { + sync_thread_t* slot; + + slot = &sync_thread_level_arrays[i]; + + /* If this slot was allocated then free the slot memory too. */ + if (slot->levels != NULL) { + free(slot->levels); + slot->levels = NULL; + } + } + + free(sync_thread_level_arrays); + sync_thread_level_arrays = NULL; +} +#endif /* UNIV_SYNC_DEBUG */ + /******************************************************************//** Frees the resources in InnoDB's own synchronization data structures. Use os_sync_free() after calling this. */ @@ -1466,17 +1559,20 @@ sync_close(void) sync_array_free(sync_primary_wait_array); - mutex = UT_LIST_GET_FIRST(mutex_list); + for (mutex = UT_LIST_GET_FIRST(mutex_list); + mutex != NULL; + /* No op */) { - while (mutex) { #ifdef UNIV_MEM_DEBUG if (mutex == &mem_hash_mutex) { mutex = UT_LIST_GET_NEXT(list, mutex); continue; } #endif /* UNIV_MEM_DEBUG */ + mutex_free(mutex); - mutex = UT_LIST_GET_FIRST(mutex_list); + + mutex = UT_LIST_GET_FIRST(mutex_list); } mutex_free(&mutex_list_mutex); @@ -1485,6 +1581,8 @@ sync_close(void) /* Switch latching order checks on in sync0sync.c */ sync_order_checks_on = FALSE; + + sync_thread_level_arrays_free(); #endif /* UNIV_SYNC_DEBUG */ sync_initialized = FALSE; |