summaryrefslogtreecommitdiff
path: root/storage/xtradb/sync/sync0sync.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb/sync/sync0sync.c')
-rw-r--r--storage/xtradb/sync/sync0sync.c535
1 files changed, 336 insertions, 199 deletions
diff --git a/storage/xtradb/sync/sync0sync.c b/storage/xtradb/sync/sync0sync.c
index 225f28df78e..4b35d6db177 100644
--- a/storage/xtradb/sync/sync0sync.c
+++ b/storage/xtradb/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
@@ -40,6 +40,10 @@ Created 9/5/1995 Heikki Tuuri
#include "srv0srv.h"
#include "buf0types.h"
#include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */
+#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
@@ -167,13 +171,13 @@ Q.E.D. */
/** The number of iterations in the mutex_spin_wait() spin loop.
Intended for performance monitoring. */
-static ib_int64_t mutex_spin_round_count = 0;
+UNIV_INTERN ib_int64_t mutex_spin_round_count = 0;
/** The number of mutex_spin_wait() calls. Intended for
performance monitoring. */
-static ib_int64_t mutex_spin_wait_count = 0;
+UNIV_INTERN ib_int64_t mutex_spin_wait_count = 0;
/** The number of OS waits in mutex_spin_wait(). Intended for
performance monitoring. */
-static ib_int64_t mutex_os_wait_count = 0;
+UNIV_INTERN ib_int64_t mutex_os_wait_count = 0;
/** The number of mutex_exit() calls. Intended for performance
monitoring. */
UNIV_INTERN ib_int64_t mutex_exit_count = 0;
@@ -185,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 */
@@ -198,6 +202,10 @@ UNIV_INTERN sync_thread_t* sync_thread_level_arrays;
/** Mutex protecting sync_thread_level_arrays */
UNIV_INTERN mutex_t sync_thread_mutex;
+
+# ifdef UNIV_PFS_MUTEX
+UNIV_INTERN mysql_pfs_key_t sync_thread_mutex_key;
+# endif /* UNIV_PFS_MUTEX */
#endif /* UNIV_SYNC_DEBUG */
/** Global list of database mutexes (not OS mutexes) created. */
@@ -206,27 +214,50 @@ UNIV_INTERN ut_list_base_node_t mutex_list;
/** Mutex protecting the mutex_list variable */
UNIV_INTERN mutex_t mutex_list_mutex;
+#ifdef UNIV_PFS_MUTEX
+UNIV_INTERN mysql_pfs_key_t mutex_list_mutex_key;
+#endif /* UNIV_PFS_MUTEX */
+
#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
@@ -238,14 +269,14 @@ void
mutex_create_func(
/*==============*/
mutex_t* mutex, /*!< in: pointer to memory */
- const char* cmutex_name, /*!< in: mutex name */
#ifdef UNIV_DEBUG
# ifdef UNIV_SYNC_DEBUG
ulint level, /*!< in: level */
# endif /* UNIV_SYNC_DEBUG */
-#endif /* UNIV_DEBUG */
const char* cfile_name, /*!< in: file name where created */
- ulint cline) /*!< in: file line where created */
+ ulint cline, /*!< in: file line where created */
+#endif /* UNIV_DEBUG */
+ const char* cmutex_name) /*!< in: mutex name */
{
#if defined(HAVE_ATOMIC_BUILTINS)
mutex_reset_lock_word(mutex);
@@ -304,13 +335,14 @@ mutex_create_func(
}
/******************************************************************//**
+NOTE! Use the corresponding macro mutex_free(), not directly this function!
Calling this function is obligatory only if the memory buffer containing
the mutex is freed. Removes a mutex object from the mutex list. The mutex
is checked to be in the reset state. */
UNIV_INTERN
void
-mutex_free(
-/*=======*/
+mutex_free_func(
+/*============*/
mutex_t* mutex) /*!< in: mutex */
{
ut_ad(mutex_validate(mutex));
@@ -745,27 +777,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 +814,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 +822,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 +850,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 +867,44 @@ 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;
- return(arr + n);
+ mutex = slot->latch;
+
+ if (mutex->magic_n == MUTEX_MAGIC_N) {
+ fprintf(stderr,
+ "Mutex '%s'\n",
+ mutex->cmutex_name);
+
+ 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,68 +915,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) {
-
- return(FALSE);
- }
+ for (i = 0; i < arr->n_elems; i++) {
+ const sync_level_t* slot;
- 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 '%s'\n",
- mutex->cmutex_name);
-
- 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);
}
}
@@ -941,31 +946,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);
}
/******************************************************************//**
@@ -979,10 +982,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) {
@@ -1002,9 +1004,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) {
@@ -1026,14 +1029,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) {
@@ -1053,9 +1053,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
@@ -1075,14 +1076,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);
}
/******************************************************************//**
@@ -1097,10 +1145,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) {
@@ -1125,20 +1173,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;
@@ -1154,24 +1205,24 @@ sync_thread_add_level(
case SYNC_TREE_NODE_FROM_HASH:
/* Do no order checking */
break;
+ case SYNC_TRX_SYS_HEADER:
+ if (srv_is_being_started) {
+ /* This is violated during trx_sys_create_rsegs()
+ when creating additional rollback segments when
+ upgrading in innobase_start_or_create_for_mysql(). */
+ break;
+ }
case SYNC_MEM_POOL:
case SYNC_MEM_HASH:
case SYNC_RECV:
case SYNC_WORK_QUEUE:
case SYNC_LOG:
+ case SYNC_LOG_FLUSH_ORDER:
case SYNC_THR_LOCAL:
case SYNC_ANY_LATCH:
- case SYNC_TRX_SYS_HEADER:
+ case SYNC_OUTER_ANY_LATCH:
case SYNC_FILE_FORMAT_TAG:
case SYNC_DOUBLEWRITE:
- case SYNC_BUF_LRU_LIST:
- case SYNC_BUF_FLUSH_LIST:
- case SYNC_BUF_PAGE_HASH:
- case SYNC_BUF_FREE_LIST:
- case SYNC_BUF_ZIP_FREE:
- case SYNC_BUF_ZIP_HASH:
- case SYNC_BUF_POOL:
- case SYNC_SEARCH_SYS:
case SYNC_SEARCH_SYS_CONF:
case SYNC_TRX_LOCK_HEAP:
case SYNC_KERNEL:
@@ -1179,7 +1230,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:
@@ -1192,13 +1243,32 @@ sync_thread_add_level(
ut_error;
}
break;
+ case SYNC_SEARCH_SYS:
+ case SYNC_BUF_LRU_LIST:
+ case SYNC_BUF_FLUSH_LIST:
+ case SYNC_BUF_PAGE_HASH:
+ case SYNC_BUF_FREE_LIST:
+ case SYNC_BUF_ZIP_FREE:
+ case SYNC_BUF_ZIP_HASH:
+ case SYNC_BUF_POOL:
+ /* We can have multiple mutexes of this type therefore we
+ can only check whether the greater than condition holds. */
+ if (!sync_thread_levels_g(array, level-1, TRUE)) {
+ fprintf(stderr,
+ "InnoDB: sync_thread_levels_g(array, %lu)"
+ " does not hold!\n", level-1);
+ ut_error;
+ }
+ break;
+
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_LRU_LIST));
+ /* the exact rule is not fixed yet, for now */
+ //ut_a(sync_thread_levels_contain(array, SYNC_BUF_LRU_LIST));
}
break;
case SYNC_REC_LOCK:
@@ -1218,8 +1288,12 @@ sync_thread_add_level(
ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1,
TRUE));
} else {
- ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP,
- TRUE));
+ /* This is violated during trx_sys_create_rsegs()
+ when creating additional rollback segments when
+ upgrading in innobase_start_or_create_for_mysql(). */
+ ut_a(srv_is_being_started
+ || sync_thread_levels_g(array, SYNC_IBUF_BITMAP,
+ TRUE));
}
break;
case SYNC_FSP_PAGE:
@@ -1230,10 +1304,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));
@@ -1286,19 +1366,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);
}
@@ -1314,8 +1401,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;
@@ -1346,17 +1432,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 = &array->elems[i];
- slot = sync_thread_levels_get_nth(array, i);
+ if (slot->latch != latch) {
+ continue;
+ }
- if (slot->latch == latch) {
- slot->latch = NULL;
+ slot->latch = NULL;
- mutex_exit(&sync_thread_mutex);
+ /* Update the free slot list. See comment in sync_level_t
+ for the level field. */
+ slot->level = array->next_free;
+ array->next_free = i;
- return(TRUE);
+ 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) {
@@ -1386,11 +1492,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;
@@ -1404,35 +1505,64 @@ 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. */
UT_LIST_INIT(mutex_list);
- mutex_create(&mutex_list_mutex, SYNC_NO_ORDER_CHECK);
+ mutex_create(mutex_list_mutex_key, &mutex_list_mutex,
+ SYNC_NO_ORDER_CHECK);
#ifdef UNIV_SYNC_DEBUG
- mutex_create(&sync_thread_mutex, SYNC_NO_ORDER_CHECK);
+ mutex_create(sync_thread_mutex_key, &sync_thread_mutex,
+ SYNC_NO_ORDER_CHECK);
#endif /* UNIV_SYNC_DEBUG */
/* Init the rw-lock list and create the mutex to protect it. */
UT_LIST_INIT(rw_lock_list);
- mutex_create(&rw_lock_list_mutex, SYNC_NO_ORDER_CHECK);
+ mutex_create(rw_lock_list_mutex_key, &rw_lock_list_mutex,
+ SYNC_NO_ORDER_CHECK);
#ifdef UNIV_SYNC_DEBUG
- mutex_create(&rw_lock_debug_mutex, SYNC_NO_ORDER_CHECK);
+ mutex_create(rw_lock_debug_mutex_key, &rw_lock_debug_mutex,
+ SYNC_NO_ORDER_CHECK);
rw_lock_debug_event = os_event_create(NULL);
rw_lock_debug_waiters = FALSE;
#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. */
@@ -1445,17 +1575,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);
@@ -1464,6 +1597,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;
@@ -1484,14 +1619,16 @@ sync_print_wait_info(
fprintf(file,
"Mutex spin waits %llu, rounds %llu, OS waits %llu\n"
- "RW-shared spins %llu, OS waits %llu;"
- " RW-excl spins %llu, OS waits %llu\n",
+ "RW-shared spins %llu, rounds %llu, OS waits %llu\n"
+ "RW-excl spins %llu, rounds %llu, OS waits %llu\n",
mutex_spin_wait_count,
mutex_spin_round_count,
mutex_os_wait_count,
rw_s_spin_wait_count,
+ rw_s_spin_round_count,
rw_s_os_wait_count,
rw_x_spin_wait_count,
+ rw_x_spin_round_count,
rw_x_os_wait_count);
fprintf(file,