diff options
Diffstat (limited to 'storage/xtradb/sync/sync0arr.cc')
-rw-r--r-- | storage/xtradb/sync/sync0arr.cc | 1564 |
1 files changed, 0 insertions, 1564 deletions
diff --git a/storage/xtradb/sync/sync0arr.cc b/storage/xtradb/sync/sync0arr.cc deleted file mode 100644 index 134d16ae58e..00000000000 --- a/storage/xtradb/sync/sync0arr.cc +++ /dev/null @@ -1,1564 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2008, Google Inc. -Copyright (c) 2013, 2015, MariaDB Corporation. All Rights Reserved. - -Portions of this file contain modifications contributed and copyrighted by -Google, Inc. Those modifications are gratefully acknowledged and are described -briefly in the InnoDB documentation. The contributions by Google are -incorporated with their permission, and subject to the conditions contained in -the file COPYING.Google. - -This program is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free Software -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file sync/sync0arr.cc -The wait array used in synchronization primitives - -Created 9/5/1995 Heikki Tuuri -*******************************************************/ - -#include "univ.i" - -#include "sync0arr.h" -#ifdef UNIV_NONINL -#include "sync0arr.ic" -#endif - -#include <mysqld_error.h> -#include <mysql/plugin.h> -#include <hash.h> -#include <myisampack.h> -#include <sql_acl.h> -#include <mysys_err.h> -#include <my_sys.h> -#include "srv0srv.h" -#include "srv0start.h" -#include "i_s.h" -#include <sql_plugin.h> -#include <innodb_priv.h> - -#include "sync0sync.h" -#include "sync0rw.h" -#include "os0sync.h" -#include "os0file.h" -#include "lock0lock.h" -#include "srv0srv.h" -#include "ha_prototypes.h" - -/* - WAIT ARRAY - ========== - -The wait array consists of cells each of which has an -an operating system event object created for it. The threads -waiting for a mutex, for example, can reserve a cell -in the array and suspend themselves to wait for the event -to become signaled. When using the wait array, remember to make -sure that some thread holding the synchronization object -will eventually know that there is a waiter in the array and -signal the object, to prevent infinite wait. -Why we chose to implement a wait array? First, to make -mutexes fast, we had to code our own implementation of them, -which only in usually uncommon cases resorts to using -slow operating system primitives. Then we had the choice of -assigning a unique OS event for each mutex, which would -be simpler, or using a global wait array. In some operating systems, -the global wait array solution is more efficient and flexible, -because we can do with a very small number of OS events, -say 200. In NT 3.51, allocating events seems to be a quadratic -algorithm, because 10 000 events are created fast, but -100 000 events takes a couple of minutes to create. - -As of 5.0.30 the above mentioned design is changed. Since now -OS can handle millions of wait events efficiently, we no longer -have this concept of each cell of wait array having one event. -Instead, now the event that a thread wants to wait on is embedded -in the wait object (mutex or rw_lock). We still keep the global -wait array for the sake of diagnostics and also to avoid infinite -wait The error_monitor thread scans the global wait array to signal -any waiting threads who have missed the signal. */ - -/** A cell where an individual thread may wait suspended -until a resource is released. The suspending is implemented -using an operating system event semaphore. */ -struct sync_cell_t { - void* wait_object; /*!< pointer to the object the - thread is waiting for; if NULL - the cell is free for use */ - void* old_wait_mutex; /*!< the latest regular or priority - wait mutex in cell */ - void* old_wait_rw_lock; - /*!< the latest regular or priority - wait rw-lock in cell */ - ulint request_type; /*!< lock type requested on the - object */ - const char* file; /*!< in debug version file where - requested */ - ulint line; /*!< in debug version line where - requested */ - os_thread_id_t thread; /*!< thread id of this waiting - thread */ - ibool waiting; /*!< TRUE if the thread has already - called sync_array_event_wait - on this cell */ - ib_int64_t signal_count; /*!< We capture the signal_count - of the wait_object when we - reset the event. This value is - then passed on to os_event_wait - and we wait only if the event - has not been signalled in the - period between the reset and - wait call. */ - time_t reservation_time;/*!< time when the thread reserved - the wait cell */ -}; - -/* NOTE: It is allowed for a thread to wait -for an event allocated for the array without owning the -protecting mutex (depending on the case: OS or database mutex), but -all changes (set or reset) to the state of the event must be made -while owning the mutex. */ -/** Synchronization array */ -struct sync_array_t { - ulint n_reserved; /*!< number of currently reserved - cells in the wait array */ - ulint n_cells; /*!< number of cells in the - wait array */ - sync_cell_t* array; /*!< pointer to wait array */ - ib_mutex_t mutex; /*!< possible database mutex - protecting this data structure */ - os_ib_mutex_t os_mutex; /*!< Possible operating system mutex - protecting the data structure. - As this data structure is used in - constructing the database mutex, - to prevent infinite recursion - in implementation, we fall back to - an OS mutex. */ - ulint res_count; /*!< count of cell reservations - since creation of the array */ -}; - -/** User configured sync array size */ -UNIV_INTERN ulong srv_sync_array_size = 32; - -/** Locally stored copy of srv_sync_array_size */ -static ulint sync_array_size; - -/** The global array of wait cells for implementation of the database's own -mutexes and read-write locks */ -static sync_array_t** sync_wait_array; - -/** count of how many times an object has been signalled */ -static ulint sg_count; - -#ifdef UNIV_SYNC_DEBUG -/******************************************************************//** -This function is called only in the debug version. Detects a deadlock -of one or more threads because of waits of semaphores. -@return TRUE if deadlock detected */ -static -ibool -sync_array_detect_deadlock( -/*=======================*/ - sync_array_t* arr, /*!< in: wait array; NOTE! the caller must - own the mutex to array */ - sync_cell_t* start, /*!< in: cell where recursive search started */ - sync_cell_t* cell, /*!< in: cell to search */ - ulint depth); /*!< in: recursion depth */ -#endif /* UNIV_SYNC_DEBUG */ - -/*****************************************************************//** -Gets the nth cell in array. -@return cell */ -sync_cell_t* -sync_array_get_nth_cell( -/*====================*/ - sync_array_t* arr, /*!< in: sync array */ - ulint n) /*!< in: index */ -{ - ut_a(arr); - ut_a(n < arr->n_cells); - - return(arr->array + n); -} - -/******************************************************************//** -Looks for a cell with the given thread id. -@return pointer to cell or NULL if not found */ -static -sync_cell_t* -sync_array_find_thread( -/*===================*/ - sync_array_t* arr, /*!< in: wait array */ - os_thread_id_t thread) /*!< in: thread id */ -{ - ulint i; - sync_cell_t* cell; - - for (i = 0; i < arr->n_cells; i++) { - - cell = sync_array_get_nth_cell(arr, i); - - if (cell->wait_object != NULL - && os_thread_eq(cell->thread, thread)) { - - return(cell); /* Found */ - } - } - - return(NULL); /* Not found */ -} - -/******************************************************************//** -Reserves the mutex semaphore protecting a sync array. */ -static -void -sync_array_enter( -/*=============*/ - sync_array_t* arr) /*!< in: sync wait array */ -{ - os_mutex_enter(arr->os_mutex); -} - -/******************************************************************//** -Releases the mutex semaphore protecting a sync array. */ -static -void -sync_array_exit( -/*============*/ - sync_array_t* arr) /*!< in: sync wait array */ -{ - os_mutex_exit(arr->os_mutex); -} - -/*******************************************************************//** -Creates a synchronization wait array. It is protected by a mutex -which is automatically reserved when the functions operating on it -are called. -@return own: created wait array */ -static -sync_array_t* -sync_array_create( -/*==============*/ - ulint n_cells) /*!< in: number of cells in the array - to create */ -{ - ulint sz; - sync_array_t* arr; - - ut_a(n_cells > 0); - - /* Allocate memory for the data structures */ - arr = static_cast<sync_array_t*>(ut_malloc(sizeof(*arr))); - memset(arr, 0x0, sizeof(*arr)); - - sz = sizeof(sync_cell_t) * n_cells; - arr->array = static_cast<sync_cell_t*>(ut_malloc(sz)); - memset(arr->array, 0x0, sz); - - arr->n_cells = n_cells; - - /* Then create the mutex to protect the wait array complex */ - arr->os_mutex = os_mutex_create(); - - return(arr); -} - -/******************************************************************//** -Frees the resources in a wait array. */ -static -void -sync_array_free( -/*============*/ - sync_array_t* arr) /*!< in, own: sync wait array */ -{ - ut_a(arr->n_reserved == 0); - - sync_array_validate(arr); - - /* Release the mutex protecting the wait array complex */ - - os_mutex_free(arr->os_mutex); - - ut_free(arr->array); - ut_free(arr); -} - -/********************************************************************//** -Validates the integrity of the wait array. Checks -that the number of reserved cells equals the count variable. */ -UNIV_INTERN -void -sync_array_validate( -/*================*/ - sync_array_t* arr) /*!< in: sync wait array */ -{ - ulint i; - sync_cell_t* cell; - ulint count = 0; - - sync_array_enter(arr); - - for (i = 0; i < arr->n_cells; i++) { - cell = sync_array_get_nth_cell(arr, i); - if (cell->wait_object != NULL) { - count++; - } - } - - ut_a(count == arr->n_reserved); - - sync_array_exit(arr); -} - -/*******************************************************************//** -Returns the event that the thread owning the cell waits for. */ -static -os_event_t -sync_cell_get_event( -/*================*/ - sync_cell_t* cell) /*!< in: non-empty sync array cell */ -{ - ulint type = cell->request_type; - - if (type == SYNC_MUTEX) { - return(&((ib_mutex_t*) cell->wait_object)->event); - } else if (type == SYNC_PRIO_MUTEX) { - return(&((ib_prio_mutex_t*) cell->wait_object) - ->high_priority_event); - } else if (type == RW_LOCK_WAIT_EX) { - return(&((rw_lock_t*) cell->wait_object)->wait_ex_event); - } else if (type == PRIO_RW_LOCK_SHARED) { - return(&((prio_rw_lock_t *) cell->wait_object) - ->high_priority_s_event); - } else if (type == PRIO_RW_LOCK_EX) { - return(&((prio_rw_lock_t *) cell->wait_object) - ->high_priority_x_event); - } else { /* RW_LOCK_SHARED and RW_LOCK_EX wait on the same event */ - ut_ad(type == RW_LOCK_SHARED || type == RW_LOCK_EX); - return(&((rw_lock_t*) cell->wait_object)->event); - } -} - -/******************************************************************//** -Reserves a wait array cell for waiting for an object. -The event of the cell is reset to nonsignalled state. -@return true if free cell is found, otherwise false */ -UNIV_INTERN -bool -sync_array_reserve_cell( -/*====================*/ - sync_array_t* arr, /*!< in: wait array */ - void* object, /*!< in: pointer to the object to wait for */ - ulint type, /*!< in: lock request type */ - const char* file, /*!< in: file where requested */ - ulint line, /*!< in: line where requested */ - ulint* index) /*!< out: index of the reserved cell */ -{ - sync_cell_t* cell; - os_event_t event; - ulint i; - - ut_a(object); - ut_a(index); - - sync_array_enter(arr); - - arr->res_count++; - - /* Reserve a new cell. */ - for (i = 0; i < arr->n_cells; i++) { - cell = sync_array_get_nth_cell(arr, i); - - if (cell->wait_object == NULL) { - - cell->waiting = FALSE; - cell->wait_object = object; - - if (type == SYNC_MUTEX || type == SYNC_PRIO_MUTEX) { - cell->old_wait_mutex = object; - } else { - cell->old_wait_rw_lock = object; - } - - cell->request_type = type; - - cell->file = file; - cell->line = line; - - arr->n_reserved++; - - *index = i; - - sync_array_exit(arr); - - /* Make sure the event is reset and also store - the value of signal_count at which the event - was reset. */ - event = sync_cell_get_event(cell); - cell->signal_count = os_event_reset(event); - - cell->reservation_time = ut_time(); - - cell->thread = os_thread_get_curr_id(); - - return(true); - } - } - - /* No free cell found */ - return false; -} - -/******************************************************************//** -This function should be called when a thread starts to wait on -a wait array cell. In the debug version this function checks -if the wait for a semaphore will result in a deadlock, in which -case prints info and asserts. */ -UNIV_INTERN -void -sync_array_wait_event( -/*==================*/ - sync_array_t* arr, /*!< in: wait array */ - ulint index) /*!< in: index of the reserved cell */ -{ - sync_cell_t* cell; - os_event_t event; - - ut_a(arr); - - sync_array_enter(arr); - - cell = sync_array_get_nth_cell(arr, index); - - ut_a(cell->wait_object); - ut_a(!cell->waiting); - ut_ad(os_thread_get_curr_id() == cell->thread); - - event = sync_cell_get_event(cell); - cell->waiting = TRUE; - -#ifdef UNIV_SYNC_DEBUG - - /* We use simple enter to the mutex below, because if - we cannot acquire it at once, mutex_enter would call - recursively sync_array routines, leading to trouble. - rw_lock_debug_mutex freezes the debug lists. */ - - rw_lock_debug_mutex_enter(); - - if (TRUE == sync_array_detect_deadlock(arr, cell, cell, 0)) { - - fputs("########################################\n", stderr); - ut_error; - } - - rw_lock_debug_mutex_exit(); -#endif - sync_array_exit(arr); - - os_event_wait_low(event, cell->signal_count); - - sync_array_free_cell(arr, index); -} - -/******************************************************************//** -Reports info of a wait array cell. */ -static -void -sync_array_cell_print( -/*==================*/ - FILE* file, /*!< in: file where to print */ - sync_cell_t* cell, /*!< in: sync cell */ - os_thread_id_t* reserver) /*!< out: write reserver or - 0 */ -{ - ib_mutex_t* mutex; - ib_prio_mutex_t* prio_mutex; - rw_lock_t* rwlock; - prio_rw_lock_t* prio_rwlock = NULL; - ulint type; - ulint writer; - - type = cell->request_type; - - fprintf(file, - "--Thread %lu has waited at %s line %lu" - " for %#.5g seconds the semaphore:\n", - (ulong) os_thread_pf(cell->thread), - innobase_basename(cell->file), (ulong) cell->line, - difftime(time(NULL), cell->reservation_time)); - - - if (type == SYNC_MUTEX || type == SYNC_PRIO_MUTEX) { - - /* We use old_wait_mutex in case the cell has already - been freed meanwhile */ - if (type == SYNC_MUTEX) { - - mutex = static_cast<ib_mutex_t*>(cell->old_wait_mutex); - } else { - - prio_mutex = static_cast<ib_prio_mutex_t*> - (cell->old_wait_mutex); - mutex = &prio_mutex->base_mutex; - } - - - if (mutex) { - fprintf(file, - "Mutex at %p '%s', lock var %lu\n" - "Last time reserved by thread " ULINTPF - " in file %s line " ULINTPF ", " - "waiters flag " ULINTPF "\n", - (void*) mutex, mutex->cmutex_name, - (ulong) mutex->lock_word, - os_thread_pf(mutex->thread_id), - mutex->file_name, mutex->line, - mutex->waiters); - } - - /* If stacktrace feature is enabled we will send a SIGUSR2 - signal to thread waiting for the semaphore. Signal handler - will then dump the current stack to error log. */ - if (srv_use_stacktrace && cell && cell->thread) { -#ifdef __linux__ - pthread_kill(cell->thread, SIGUSR2); -#endif - } - - if (type == SYNC_PRIO_MUTEX) { - - fprintf(file, - "high-priority waiters count %lu\n", - (ulong) prio_mutex->high_priority_waiters); - } - - } else if (type == RW_LOCK_EX - || type == RW_LOCK_WAIT_EX - || type == RW_LOCK_SHARED - || type == PRIO_RW_LOCK_SHARED - || type == PRIO_RW_LOCK_EX) { - - fputs((type == RW_LOCK_EX || type == PRIO_RW_LOCK_EX) - ? "X-lock on" - : type == RW_LOCK_WAIT_EX ? "X-lock (wait_ex) on" - : "S-lock on", file); - - /* Currently we are unable to tell high priority - RW_LOCK_WAIT_EX waiter from a regular priority one. Assume - it's a regular one. */ - if (type == RW_LOCK_EX || type == RW_LOCK_WAIT_EX - || type == RW_LOCK_SHARED) { - - rwlock = static_cast<rw_lock_t *> - (cell->old_wait_rw_lock); - } else { - - prio_rwlock = static_cast<prio_rw_lock_t *> - (cell->old_wait_rw_lock); - rwlock = &prio_rwlock->base_lock; - } - - if (rwlock) { - fprintf(file, - " RW-latch at %p '%s'\n", - (void*) rwlock, rwlock->lock_name); - - writer = rw_lock_get_writer(rwlock); - - if (writer && writer != RW_LOCK_NOT_LOCKED) { - fprintf(file, - "a writer (thread id " ULINTPF ") has" - " reserved it in mode %s", - os_thread_pf(rwlock->writer_thread), - writer == RW_LOCK_EX - ? " exclusive\n" - : " wait exclusive\n"); - - *reserver = rwlock->writer_thread; - } - - fprintf(file, - "number of readers " ULINTPF - ", waiters flag " ULINTPF ", " - "lock_word: %lx\n" - "Last time read locked in file %s line %u\n" - "Last time write locked in file %s line %u\n" - "Holder thread " ULINTPF - " file %s line " ULINTPF "\n", - rw_lock_get_reader_count(rwlock), - rwlock->waiters, - rwlock->lock_word, - innobase_basename(rwlock->last_s_file_name), - rwlock->last_s_line, - innobase_basename(rwlock->last_x_file_name), - rwlock->last_x_line, - os_thread_pf(rwlock->thread_id), - innobase_basename(rwlock->file_name), - rwlock->line); - - /* If stacktrace feature is enabled we will send a SIGUSR2 - signal to thread that has locked RW-latch with write mode. - Signal handler will then dump the current stack to error log. */ - if (writer != RW_LOCK_NOT_LOCKED && srv_use_stacktrace && - rwlock && rwlock->writer_thread) { -#ifdef __linux__ - pthread_kill(rwlock->writer_thread, SIGUSR2); -#endif - } - } - - if (prio_rwlock) { - fprintf(file, "high priority S waiters count %lu, " - "high priority X waiters count %lu, " - "wait-exclusive waiter is " - "high priority if exists: %lu\n", - prio_rwlock->high_priority_s_waiters, - prio_rwlock->high_priority_x_waiters, - prio_rwlock->high_priority_wait_ex_waiter); - } - } else { - ut_error; - } - - if (!cell->waiting) { - fputs("wait has ended\n", file); - } -} - -#ifdef UNIV_SYNC_DEBUG - -/******************************************************************//** -Recursion step for deadlock detection. -@return TRUE if deadlock detected */ -static -ibool -sync_array_deadlock_step( -/*=====================*/ - sync_array_t* arr, /*!< in: wait array; NOTE! the caller must - own the mutex to array */ - sync_cell_t* start, /*!< in: cell where recursive search - started */ - os_thread_id_t thread, /*!< in: thread to look at */ - ulint pass, /*!< in: pass value */ - ulint depth) /*!< in: recursion depth */ -{ - sync_cell_t* new_cell; - - if (pass != 0) { - /* If pass != 0, then we do not know which threads are - responsible of releasing the lock, and no deadlock can - be detected. */ - - return(FALSE); - } - - new_cell = sync_array_find_thread(arr, thread); - - if (new_cell == start) { - /* Deadlock */ - fputs("########################################\n" - "DEADLOCK of threads detected!\n", stderr); - - return(TRUE); - - } else if (new_cell) { - return(sync_array_detect_deadlock( - arr, start, new_cell, depth + 1)); - } - return(FALSE); -} - -/******************************************************************//** -This function is called only in the debug version. Detects a deadlock -of one or more threads because of waits of semaphores. -@return TRUE if deadlock detected */ -static -ibool -sync_array_detect_deadlock( -/*=======================*/ - sync_array_t* arr, /*!< in: wait array; NOTE! the caller must - own the mutex to array */ - sync_cell_t* start, /*!< in: cell where recursive search started */ - sync_cell_t* cell, /*!< in: cell to search */ - ulint depth) /*!< in: recursion depth */ -{ - ib_mutex_t* mutex; - rw_lock_t* lock; - os_thread_id_t thread; - ibool ret; - rw_lock_debug_t*debug; - os_thread_id_t r = 0; - - ut_a(arr); - ut_a(start); - ut_a(cell); - ut_ad(cell->wait_object); - ut_ad(os_thread_get_curr_id() == start->thread); - ut_ad(depth < 100); - - depth++; - - if (!cell->waiting) { - - return(FALSE); /* No deadlock here */ - } - - if (cell->request_type == SYNC_MUTEX - || cell->request_type == SYNC_PRIO_MUTEX) { - - if (cell->request_type == SYNC_MUTEX) { - mutex = static_cast<ib_mutex_t*>(cell->wait_object); - } else { - mutex = &(static_cast<ib_prio_mutex_t*>( - cell->wait_object))->base_mutex; - } - - if (mutex_get_lock_word(mutex) != 0) { - - thread = mutex->thread_id; - - /* Note that mutex->thread_id above may be - also OS_THREAD_ID_UNDEFINED, because the - thread which held the mutex maybe has not - yet updated the value, or it has already - released the mutex: in this case no deadlock - can occur, as the wait array cannot contain - a thread with ID_UNDEFINED value. */ - - ret = sync_array_deadlock_step(arr, start, thread, 0, - depth); - if (ret) { - fprintf(stderr, - "Mutex %p owned by thread %lu file %s line %lu\n", - mutex, (ulong) os_thread_pf(mutex->thread_id), - mutex->file_name, (ulong) mutex->line); - sync_array_cell_print(stderr, cell, &r); - - return(TRUE); - } - } - - return(FALSE); /* No deadlock */ - - } else if (cell->request_type == RW_LOCK_EX - || cell->request_type == PRIO_RW_LOCK_EX - || cell->request_type == RW_LOCK_WAIT_EX) { - - lock = static_cast<rw_lock_t*>(cell->wait_object); - - for (debug = UT_LIST_GET_FIRST(lock->debug_list); - debug != 0; - debug = UT_LIST_GET_NEXT(list, debug)) { - - thread = debug->thread_id; - - if (((debug->lock_type == RW_LOCK_EX) - && !os_thread_eq(thread, cell->thread)) - || ((debug->lock_type == RW_LOCK_WAIT_EX) - && !os_thread_eq(thread, cell->thread)) - || (debug->lock_type == RW_LOCK_SHARED)) { - - /* The (wait) x-lock request can block - infinitely only if someone (can be also cell - thread) is holding s-lock, or someone - (cannot be cell thread) (wait) x-lock, and - he is blocked by start thread */ - - ret = sync_array_deadlock_step( - arr, start, thread, debug->pass, - depth); - if (ret) { -print: - fprintf(stderr, "rw-lock %p ", - (void*) lock); - sync_array_cell_print(stderr, cell, &r); - rw_lock_debug_print(stderr, debug); - return(TRUE); - } - } - } - - return(FALSE); - - } else if (cell->request_type == RW_LOCK_SHARED - || cell->request_type == PRIO_RW_LOCK_SHARED) { - - lock = static_cast<rw_lock_t*>(cell->wait_object); - - for (debug = UT_LIST_GET_FIRST(lock->debug_list); - debug != 0; - debug = UT_LIST_GET_NEXT(list, debug)) { - - thread = debug->thread_id; - - if ((debug->lock_type == RW_LOCK_EX) - || (debug->lock_type == RW_LOCK_WAIT_EX)) { - - /* The s-lock request can block infinitely - only if someone (can also be cell thread) is - holding (wait) x-lock, and he is blocked by - start thread */ - - ret = sync_array_deadlock_step( - arr, start, thread, debug->pass, - depth); - if (ret) { - goto print; - } - } - } - - return(FALSE); - - } else { - ut_error; - } - - return(TRUE); /* Execution never reaches this line: for compiler - fooling only */ -} -#endif /* UNIV_SYNC_DEBUG */ - -/******************************************************************//** -Determines if we can wake up the thread waiting for a sempahore. */ -static -ibool -sync_arr_cell_can_wake_up( -/*======================*/ - sync_cell_t* cell) /*!< in: cell to search */ -{ - ib_mutex_t* mutex; - rw_lock_t* lock; - - if (cell->request_type == SYNC_MUTEX - || cell->request_type == SYNC_PRIO_MUTEX) { - - if (cell->request_type == SYNC_MUTEX) { - mutex = static_cast<ib_mutex_t*>(cell->wait_object); - } else { - mutex = &(static_cast<ib_prio_mutex_t*>( - cell->wait_object))->base_mutex; - } - - os_rmb; - if (mutex_get_lock_word(mutex) == 0) { - - return(TRUE); - } - - } else if (cell->request_type == RW_LOCK_EX - || cell->request_type == PRIO_RW_LOCK_EX) { - - lock = static_cast<rw_lock_t*>(cell->wait_object); - - os_rmb; - if (lock->lock_word > 0) { - /* Either unlocked or only read locked. */ - - return(TRUE); - } - - } else if (cell->request_type == RW_LOCK_WAIT_EX) { - - lock = static_cast<rw_lock_t*>(cell->wait_object); - - /* lock_word == 0 means all readers have left */ - os_rmb; - if (lock->lock_word == 0) { - - return(TRUE); - } - } else if (cell->request_type == RW_LOCK_SHARED - || cell->request_type == PRIO_RW_LOCK_SHARED) { - lock = static_cast<rw_lock_t*>(cell->wait_object); - - /* lock_word > 0 means no writer or reserved writer */ - os_rmb; - if (lock->lock_word > 0) { - - return(TRUE); - } - } else { - - ut_error; - } - - return(FALSE); -} - -/******************************************************************//** -Frees the cell. NOTE! sync_array_wait_event frees the cell -automatically! */ -UNIV_INTERN -void -sync_array_free_cell( -/*=================*/ - sync_array_t* arr, /*!< in: wait array */ - ulint index) /*!< in: index of the cell in array */ -{ - sync_cell_t* cell; - - sync_array_enter(arr); - - cell = sync_array_get_nth_cell(arr, index); - - ut_a(cell->wait_object != NULL); - - cell->waiting = FALSE; - cell->wait_object = NULL; - cell->signal_count = 0; - - ut_a(arr->n_reserved > 0); - arr->n_reserved--; - - sync_array_exit(arr); -} - -/**********************************************************************//** -Increments the signalled count. */ -UNIV_INTERN -void -sync_array_object_signalled(void) -/*=============================*/ -{ -#ifdef HAVE_ATOMIC_BUILTINS - (void) os_atomic_increment_ulint(&sg_count, 1); -#else - ++sg_count; -#endif /* HAVE_ATOMIC_BUILTINS */ -} - -/**********************************************************************//** -If the wakeup algorithm does not work perfectly at semaphore relases, -this function will do the waking (see the comment in mutex_exit). This -function should be called about every 1 second in the server. - -Note that there's a race condition between this thread and mutex_exit -changing the lock_word and calling signal_object, so sometimes this finds -threads to wake up even when nothing has gone wrong. */ -static -void -sync_array_wake_threads_if_sema_free_low( -/*=====================================*/ - sync_array_t* arr) /* in/out: wait array */ -{ - ulint i = 0; - ulint count; - - sync_array_enter(arr); - - for (count = 0; count < arr->n_reserved; ++i) { - sync_cell_t* cell; - - cell = sync_array_get_nth_cell(arr, i); - - if (cell->wait_object != NULL) { - - count++; - - if (sync_arr_cell_can_wake_up(cell)) { - os_event_t event; - - event = sync_cell_get_event(cell); - - os_event_set(event); - } - } - } - - sync_array_exit(arr); -} - -/**********************************************************************//** -If the wakeup algorithm does not work perfectly at semaphore relases, -this function will do the waking (see the comment in mutex_exit). This -function should be called about every 1 second in the server. - -Note that there's a race condition between this thread and mutex_exit -changing the lock_word and calling signal_object, so sometimes this finds -threads to wake up even when nothing has gone wrong. */ -UNIV_INTERN -void -sync_arr_wake_threads_if_sema_free(void) -/*====================================*/ -{ - ulint i; - - for (i = 0; i < sync_array_size; ++i) { - - sync_array_wake_threads_if_sema_free_low( - sync_wait_array[i]); - } -} - -/**********************************************************************//** -Prints warnings of long semaphore waits to stderr. -@return TRUE if fatal semaphore wait threshold was exceeded */ -static -ibool -sync_array_print_long_waits_low( -/*============================*/ - sync_array_t* arr, /*!< in: sync array instance */ - os_thread_id_t* waiter, /*!< out: longest waiting thread */ - const void** sema, /*!< out: longest-waited-for semaphore */ - ibool* noticed)/*!< out: TRUE if long wait noticed */ -{ - ulint i; - ulint fatal_timeout = srv_fatal_semaphore_wait_threshold; - ibool fatal = FALSE; - double longest_diff = 0; - - /* For huge tables, skip the check during CHECK TABLE etc... */ - if (fatal_timeout > SRV_SEMAPHORE_WAIT_EXTENSION) { - return(FALSE); - } - -#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 < arr->n_cells; i++) { - - double diff; - sync_cell_t* cell; - void* wait_object; - os_thread_id_t reserver=0; - - cell = sync_array_get_nth_cell(arr, i); - - 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, &reserver); - *noticed = TRUE; - } - - if (diff > fatal_timeout) { - fatal = TRUE; - } - - if (diff > longest_diff) { - longest_diff = diff; - *sema = wait_object; - *waiter = cell->thread; - } - } - - /* We found a long semaphore wait, wait all threads that are - waiting for a semaphore. */ - if (*noticed) { - for (i = 0; i < arr->n_cells; i++) { - void* wait_object; - sync_cell_t* cell; - os_thread_id_t reserver=(os_thread_id_t)ULINT_UNDEFINED; - ulint loop=0; - - cell = sync_array_get_nth_cell(arr, i); - - wait_object = cell->wait_object; - - if (wait_object == NULL || !cell->waiting) { - - continue; - } - - fputs("InnoDB: Warning: semaphore wait:\n", - stderr); - sync_array_cell_print(stderr, cell, &reserver); - - /* Try to output cell information for writer recursive way */ - while (reserver != (os_thread_id_t)ULINT_UNDEFINED) { - sync_cell_t* reserver_wait; - - reserver_wait = sync_array_find_thread(arr, reserver); - - if (reserver_wait && - reserver_wait->wait_object != NULL && - reserver_wait->waiting) { - fputs("InnoDB: Warning: Writer thread is waiting this semaphore:\n", - stderr); - sync_array_cell_print(stderr, reserver_wait, &reserver); - - if (reserver_wait->thread == reserver) { - reserver = (os_thread_id_t)ULINT_UNDEFINED; - } - } else { - reserver = (os_thread_id_t)ULINT_UNDEFINED; - } - - /* This is protection against loop */ - if (loop > 100) { - fputs("InnoDB: Warning: Too many waiting threads.\n", stderr); - break; - } - } - } - } - -#undef SYNC_ARRAY_TIMEOUT - - return(fatal); -} - -/**********************************************************************//** -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( -/*========================*/ - os_thread_id_t* waiter, /*!< out: longest waiting thread */ - const void** sema) /*!< out: longest-waited-for semaphore */ -{ - ulint i; - ibool fatal = FALSE; - ibool noticed = FALSE; - - for (i = 0; i < sync_array_size; ++i) { - - sync_array_t* arr = sync_wait_array[i]; - - sync_array_enter(arr); - - if (sync_array_print_long_waits_low( - arr, waiter, sema, ¬iced)) { - - fatal = TRUE; - } - - sync_array_exit(arr); - } - - if (noticed) { - ibool old_val; - - fprintf(stderr, - "InnoDB: ###### Starts InnoDB Monitor" - " for 30 secs to print diagnostic info:\n"); - - old_val = srv_print_innodb_monitor; - - /* If some crucial semaphore is reserved, then also the InnoDB - Monitor can hang, and we do not get diagnostics. Since in - many cases an InnoDB hang is caused by a pwrite() or a pread() - call hanging inside the operating system, let us print right - now the values of pending calls of these. */ - - fprintf(stderr, - "InnoDB: Pending reads " UINT64PF - ", writes " UINT64PF "\n", - MONITOR_VALUE(MONITOR_OS_PENDING_READS), - MONITOR_VALUE(MONITOR_OS_PENDING_WRITES)); - - srv_print_innodb_monitor = TRUE; - os_event_set(srv_monitor_event); - - os_thread_sleep(30000000); - - srv_print_innodb_monitor = static_cast<my_bool>(old_val); - fprintf(stderr, - "InnoDB: ###### Diagnostic info printed" - " to the standard error stream\n"); - } - - return(fatal); -} - -/**********************************************************************//** -Prints info of the wait array. */ -static -void -sync_array_print_info_low( -/*======================*/ - FILE* file, /*!< in: file where to print */ - sync_array_t* arr) /*!< in: wait array */ -{ - ulint i; - ulint count = 0; - - fprintf(file, - "OS WAIT ARRAY INFO: reservation count " ULINTPF "\n", - arr->res_count); - - for (i = 0; count < arr->n_reserved; ++i) { - sync_cell_t* cell; - os_thread_id_t r = 0; - - cell = sync_array_get_nth_cell(arr, i); - - if (cell->wait_object != NULL) { - count++; - sync_array_cell_print(file, cell, &r); - } - } -} - -/**********************************************************************//** -Prints info of the wait array. */ -static -void -sync_array_print_info( -/*==================*/ - FILE* file, /*!< in: file where to print */ - sync_array_t* arr) /*!< in: wait array */ -{ - sync_array_enter(arr); - - sync_array_print_info_low(file, arr); - - sync_array_exit(arr); -} - -/**********************************************************************//** -Create the primary system wait array(s), they are protected by an OS mutex */ -UNIV_INTERN -void -sync_array_init( -/*============*/ - ulint n_threads) /*!< in: Number of slots to - create in all arrays */ -{ - ulint i; - ulint n_slots; - - ut_a(sync_wait_array == NULL); - ut_a(srv_sync_array_size > 0); - ut_a(n_threads > 0); - - sync_array_size = srv_sync_array_size; - - /* We have to use ut_malloc() because the mutex infrastructure - hasn't been initialised yet. It is required by mem_alloc() and - the heap functions. */ - - sync_wait_array = static_cast<sync_array_t**>( - ut_malloc(sizeof(*sync_wait_array) * sync_array_size)); - - n_slots = 1 + (n_threads - 1) / sync_array_size; - - for (i = 0; i < sync_array_size; ++i) { - - sync_wait_array[i] = sync_array_create(n_slots); - } -} - -/**********************************************************************//** -Close sync array wait sub-system. */ -UNIV_INTERN -void -sync_array_close(void) -/*==================*/ -{ - ulint i; - - for (i = 0; i < sync_array_size; ++i) { - sync_array_free(sync_wait_array[i]); - } - - ut_free(sync_wait_array); - sync_wait_array = NULL; -} - -/**********************************************************************//** -Print info about the sync array(s). */ -UNIV_INTERN -void -sync_array_print( -/*=============*/ - FILE* file) /*!< in/out: Print to this stream */ -{ - ulint i; - - for (i = 0; i < sync_array_size; ++i) { - sync_array_print_info(file, sync_wait_array[i]); - } - - fprintf(file, - "OS WAIT ARRAY INFO: signal count " ULINTPF "\n", sg_count); - -} - -/**********************************************************************//** -Get an instance of the sync wait array. */ -UNIV_INTERN -sync_array_t* -sync_array_get(void) -/*================*/ -{ - ulint i; - static ulint count; - -#ifdef HAVE_ATOMIC_BUILTINS - i = os_atomic_increment_ulint(&count, 1); -#else - i = count++; -#endif /* HAVE_ATOMIC_BUILTINS */ - - return(sync_wait_array[i % sync_array_size]); -} - -/**********************************************************************//** -Prints info of the wait array without using any mutexes/semaphores. */ -UNIV_INTERN -void -sync_array_print_xtradb(void) -/*=========================*/ -{ - ulint i; - sync_array_t* arr = sync_array_get(); - - fputs("InnoDB: Semaphore wait debug output started for XtraDB:\n", stderr); - - for (i = 0; i < arr->n_cells; i++) { - void* wait_object; - sync_cell_t* cell; - os_thread_id_t reserver=(os_thread_id_t)ULINT_UNDEFINED; - ulint loop=0; - - cell = sync_array_get_nth_cell(arr, i); - - wait_object = cell->wait_object; - - if (wait_object == NULL || !cell->waiting) { - - continue; - } - - fputs("InnoDB: Warning: semaphore wait:\n", - stderr); - sync_array_cell_print(stderr, cell, &reserver); - - /* Try to output cell information for writer recursive way */ - while (reserver != (os_thread_id_t)ULINT_UNDEFINED) { - sync_cell_t* reserver_wait; - - reserver_wait = sync_array_find_thread(arr, reserver); - - if (reserver_wait && - reserver_wait->wait_object != NULL && - reserver_wait->waiting) { - fputs("InnoDB: Warning: Writer thread is waiting this semaphore:\n", - stderr); - sync_array_cell_print(stderr, reserver_wait, &reserver); - - if (reserver_wait->thread == reserver) { - reserver = (os_thread_id_t)ULINT_UNDEFINED; - } - } else { - reserver = (os_thread_id_t)ULINT_UNDEFINED; - } - - /* This is protection against loop */ - if (loop > 100) { - fputs("InnoDB: Warning: Too many waiting threads.\n", stderr); - break; - } - } - } - - fputs("InnoDB: Semaphore wait debug output ended:\n", stderr); -} - -/**********************************************************************//** -Get number of items on sync array. */ -UNIV_INTERN -ulint -sync_arr_get_n_items(void) -/*======================*/ -{ - sync_array_t* sync_arr = sync_array_get(); - return (ulint) sync_arr->n_cells; -} - -/******************************************************************//** -Get specified item from sync array if it is reserved. Set given -pointer to array item if it is reserved. -@return true if item is reserved, false othervise */ -UNIV_INTERN -ibool -sync_arr_get_item( -/*==============*/ - ulint i, /*!< in: requested item */ - sync_cell_t **cell) /*!< out: cell contents if item - reserved */ -{ - sync_array_t* sync_arr; - sync_cell_t* wait_cell; - void* wait_object; - ibool found = FALSE; - - sync_arr = sync_array_get(); - wait_cell = sync_array_get_nth_cell(sync_arr, i); - - if (wait_cell) { - wait_object = wait_cell->wait_object; - - if(wait_object != NULL && wait_cell->waiting) { - found = TRUE; - *cell = wait_cell; - } - } - - return found; -} - -/*******************************************************************//** -Function to populate INFORMATION_SCHEMA.INNODB_SYS_SEMAPHORE_WAITS table. -Loop through each item on sync array, and extract the column -information and fill the INFORMATION_SCHEMA.INNODB_SYS_SEMAPHORE_WAITS table. -@return 0 on success */ -UNIV_INTERN -int -sync_arr_fill_sys_semphore_waits_table( -/*===================================*/ - THD* thd, /*!< in: thread */ - TABLE_LIST* tables, /*!< in/out: tables to fill */ - Item* ) /*!< in: condition (not used) */ -{ - Field** fields; - ulint n_items; - - DBUG_ENTER("i_s_sys_semaphore_waits_fill_table"); - RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name); - - /* deny access to user without PROCESS_ACL privilege */ - if (check_global_access(thd, PROCESS_ACL)) { - DBUG_RETURN(0); - } - - fields = tables->table->field; - n_items = sync_arr_get_n_items(); - ulint type; - - for(ulint i=0; i < n_items;i++) { - sync_cell_t *cell=NULL; - if (sync_arr_get_item(i, &cell)) { - ib_prio_mutex_t* prio_mutex; - ib_mutex_t* mutex; - type = cell->request_type; - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_THREAD_ID], (longlong)os_thread_pf(cell->thread))); - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_FILE], innobase_basename(cell->file))); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_LINE], cell->line)); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_WAIT_TIME], (longlong)difftime(time(NULL), cell->reservation_time))); - - if (type == SYNC_MUTEX || type == SYNC_PRIO_MUTEX) { - if (type == SYNC_MUTEX) { - mutex = static_cast<ib_mutex_t*>(cell->old_wait_mutex); - } else { - - prio_mutex = static_cast<ib_prio_mutex_t*> - (cell->old_wait_mutex); - mutex = &prio_mutex->base_mutex; - } - - if (mutex) { - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_OBJECT_NAME], mutex->cmutex_name)); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_WAIT_OBJECT], (longlong)mutex)); - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_WAIT_TYPE], "MUTEX")); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_HOLDER_THREAD_ID], (longlong)mutex->thread_id)); - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_HOLDER_FILE], innobase_basename(mutex->file_name))); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_HOLDER_LINE], mutex->line)); - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_CREATED_FILE], innobase_basename(mutex->cfile_name))); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_CREATED_LINE], mutex->cline)); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_WAITERS_FLAG], (longlong)mutex->waiters)); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_LOCK_WORD], (longlong)mutex->lock_word)); - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_LAST_WRITER_FILE], innobase_basename(mutex->file_name))); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_LAST_WRITER_LINE], mutex->line)); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_OS_WAIT_COUNT], mutex->count_os_wait)); - } - } else if (type == RW_LOCK_EX - || type == RW_LOCK_WAIT_EX - || type == RW_LOCK_SHARED - || type == PRIO_RW_LOCK_SHARED - || type == PRIO_RW_LOCK_EX) { - rw_lock_t* rwlock=NULL; - prio_rw_lock_t* prio_rwlock=NULL; - - if (type == RW_LOCK_EX || type == RW_LOCK_WAIT_EX - || type == RW_LOCK_SHARED) { - - rwlock = static_cast<rw_lock_t *> - (cell->old_wait_rw_lock); - } else { - - prio_rwlock = static_cast<prio_rw_lock_t *> - (cell->old_wait_rw_lock); - rwlock = &prio_rwlock->base_lock; - } - - if (rwlock) { - ulint writer = rw_lock_get_writer(rwlock); - - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_WAIT_OBJECT], (longlong)rwlock)); - if (type == RW_LOCK_EX) { - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_WAIT_TYPE], "RW_LOCK_EX")); - } else if (type == RW_LOCK_WAIT_EX) { - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_WAIT_TYPE], "RW_LOCK_WAIT_EX")); - } else if (type == RW_LOCK_SHARED) { - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_WAIT_TYPE], "RW_LOCK_SHARED")); - } - - if (writer != RW_LOCK_NOT_LOCKED) { - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_OBJECT_NAME], rwlock->lock_name)); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_WRITER_THREAD], (longlong)os_thread_pf(rwlock->writer_thread))); - - if (writer == RW_LOCK_EX) { - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_RESERVATION_MODE], "RW_LOCK_EX")); - } else if (writer == RW_LOCK_WAIT_EX) { - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_RESERVATION_MODE], "RW_LOCK_WAIT_EX")); - } - - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_HOLDER_THREAD_ID], (longlong)rwlock->thread_id)); - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_HOLDER_FILE], innobase_basename(rwlock->file_name))); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_HOLDER_LINE], rwlock->line)); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_READERS], rw_lock_get_reader_count(rwlock))); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_WAITERS_FLAG], (longlong)rwlock->waiters)); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_LOCK_WORD], (longlong)rwlock->lock_word)); - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_LAST_READER_FILE], innobase_basename(rwlock->last_s_file_name))); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_LAST_READER_LINE], rwlock->last_s_line)); - OK(field_store_string(fields[SYS_SEMAPHORE_WAITS_LAST_WRITER_FILE], innobase_basename(rwlock->last_x_file_name))); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_LAST_WRITER_LINE], rwlock->last_x_line)); - OK(field_store_ulint(fields[SYS_SEMAPHORE_WAITS_OS_WAIT_COUNT], rwlock->count_os_wait)); - } - } - } - - OK(schema_table_store_record(thd, tables->table)); - } - } - - DBUG_RETURN(0); -} |