diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h index b66327a394c..39f8d07af89 100644 --- a/storage/innobase/include/que0que.h +++ b/storage/innobase/include/que0que.h @@ -381,9 +381,6 @@ struct que_thr_struct{ thus far */ ulint lock_state; /*!< lock state of thread (table or row) */ - struct srv_slot_struct* - slot; /* The thread slot in the wait - array in srv_sys_t */ }; #define QUE_THR_MAGIC_N 8476583 diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 75af697e046..98e127d41e2 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -239,6 +239,7 @@ extern ibool srv_print_latch_waits; # define srv_print_latch_waits FALSE #endif /* UNIV_DEBUG */ +extern ulint srv_activity_count; extern ulint srv_fatal_semaphore_wait_threshold; extern ulint srv_dml_needed_delay; @@ -313,6 +314,12 @@ typedef struct export_var_struct export_struc; /** Status variables to be passed to MySQL */ extern export_struc export_vars; +/** The server system */ +typedef struct srv_sys_struct srv_sys_t; + +/** The server system */ +extern srv_sys_t* srv_sys; + # ifdef UNIV_PFS_THREAD /* Keys to register InnoDB threads with performance schema */ extern mysql_pfs_key_t trx_rollback_clean_thread_key; @@ -414,8 +421,6 @@ enum srv_thread_type { be biggest) */ }; -struct srv_slot_struct; - /*********************************************************************//** Boots Innobase server. @return DB_SUCCESS or error code */ @@ -466,6 +471,17 @@ srv_set_io_thread_op_info( const char* str); /*!< in: constant char string describing the state */ /*********************************************************************//** +Releases threads of the type given from suspension in the thread table. +NOTE! The server mutex has to be reserved by the caller! +@return number of threads released: this may be less than n if not +enough threads were suspended at the moment */ +UNIV_INTERN +ulint +srv_release_threads( +/*================*/ + enum srv_thread_type type, /*!< in: thread type */ + ulint n); /*!< in: number of threads to release */ +/*********************************************************************//** The master thread controlling the server. @return a dummy parameter */ UNIV_INTERN @@ -612,13 +628,6 @@ void srv_export_innodb_status(void); /*==========================*/ -/******************************************************************//** -Increment the server activity counter. */ -UNIV_INTERN -void -srv_inc_activity_count(void); -/*=========================*/ - /*********************************************************************//** Asynchronous purge thread. @return a dummy parameter */ @@ -700,6 +709,20 @@ struct export_var_struct{ ulint innodb_rows_deleted; /*!< srv_n_rows_deleted */ }; +/** Thread slot in the thread table */ +typedef struct srv_slot_struct srv_slot_t; + +/** Thread table is an array of slots */ +typedef srv_slot_t srv_table_t; + +/** The server system struct */ +struct srv_sys_struct{ + srv_table_t* threads; /*!< server thread table */ + UT_LIST_BASE_NODE_T(que_thr_t) + tasks; /*!< task queue */ +}; + +extern ulint srv_n_threads_active[]; #else /* !UNIV_HOTBACKUP */ # define srv_use_adaptive_hash_indexes FALSE # define srv_use_checksums TRUE diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 09b1aa052e5..4e73bee9108 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -105,7 +105,6 @@ extern mysql_pfs_key_t rw_lock_mutex_key; extern mysql_pfs_key_t srv_dict_tmpfile_mutex_key; extern mysql_pfs_key_t srv_innodb_monitor_mutex_key; extern mysql_pfs_key_t srv_misc_tmpfile_mutex_key; -extern mysql_pfs_key_t srv_threads_mutex_key; extern mysql_pfs_key_t srv_monitor_file_mutex_key; extern mysql_pfs_key_t syn_arr_mutex_key; # ifdef UNIV_SYNC_DEBUG @@ -588,9 +587,6 @@ Kernel mutex If a kernel operation needs a file | fsp x-latch before acquiring the kernel | mutex. V -Threads mutex Thread scheduling mutex -| -V Search system mutex | V @@ -661,9 +657,8 @@ or row lock! */ /*------------------------------------- MySQL binlog mutex */ /*-------------------------------*/ #define SYNC_KERNEL 300 -#define SYNC_THREADS 299 -#define SYNC_REC_LOCK 298 -#define SYNC_TRX_LOCK_HEAP 297 +#define SYNC_REC_LOCK 299 +#define SYNC_TRX_LOCK_HEAP 298 #define SYNC_TRX_SYS_HEADER 290 #define SYNC_LOG 170 #define SYNC_LOG_FLUSH_ORDER 147 diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index 96faa84c6ff..6bde8308052 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -245,6 +245,9 @@ by one. */ #define UNIV_SET_MEM_TO_ZERO #endif +#define UNIV_DEBUG +#define UNIV_SYNC_DEBUG + /* #define UNIV_SQL_DEBUG #define UNIV_LOG_DEBUG diff --git a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c index e4f7c8edca1..2fe046fa9b8 100644 --- a/storage/innobase/que/que0que.c +++ b/storage/innobase/que/que0que.c @@ -29,6 +29,7 @@ Created 5/27/1996 Heikki Tuuri #include "que0que.ic" #endif +#include "srv0que.h" #include "usr0sess.h" #include "trx0trx.h" #include "trx0roll.h" @@ -225,8 +226,6 @@ que_thr_create( thr->resource = 0; thr->lock_state = QUE_THR_LOCK_NOLOCK; - thr->slot = NULL; - UT_LIST_ADD_LAST(thrs, parent->thrs, thr); return(thr); @@ -312,9 +311,7 @@ que_thr_end_wait_no_next_thr( /* In MySQL we let the OS thread (not just the query thread) to wait for the lock to be released: */ - if (thr != NULL) { - srv_release_mysql_thread_if_suspended(thr); - } + srv_release_mysql_thread_if_suspended(thr); /* srv_que_task_enqueue_low(thr); */ } diff --git a/storage/innobase/row/row0undo.c b/storage/innobase/row/row0undo.c index 072a102a389..3d739c9689a 100644 --- a/storage/innobase/row/row0undo.c +++ b/storage/innobase/row/row0undo.c @@ -341,7 +341,7 @@ row_undo_step( ut_ad(thr); - srv_inc_activity_count(); + srv_activity_count++; trx = thr_get_trx(thr); diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index fac5277aaa9..9342d2987bd 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -68,6 +68,7 @@ Created 10/8/1995 Heikki Tuuri #include "sync0sync.h" #include "thr0loc.h" #include "que0que.h" +#include "srv0que.h" #include "log0recv.h" #include "pars0pars.h" #include "usr0sess.h" @@ -89,6 +90,10 @@ Created 10/8/1995 Heikki Tuuri affects only FOREIGN KEY definition parsing */ UNIV_INTERN ibool srv_lower_case_table_names = FALSE; +/* The following counter is incremented whenever there is some user activity +in the server */ +UNIV_INTERN ulint srv_activity_count = 0; + /* The following is the maximum allowed duration of a lock wait. */ UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600; @@ -319,18 +324,16 @@ concurrency check. */ UNIV_INTERN ulong srv_thread_concurrency = 0; +/* this mutex protects srv_conc data structures */ +UNIV_INTERN os_fast_mutex_t srv_conc_mutex; /* number of transactions that have declared_to_be_inside_innodb set. It used to be a non-error for this value to drop below zero temporarily. This is no longer true. We'll, however, keep the lint datatype to add assertions to catch any corner cases that we may have missed. */ UNIV_INTERN lint srv_conc_n_threads = 0; - -/* this mutex protects srv_conc data structures */ -static os_fast_mutex_t srv_conc_mutex; - /* number of OS threads waiting in the FIFO for a permission to enter InnoDB */ -static ulint srv_conc_n_waiting_threads = 0; +UNIV_INTERN ulint srv_conc_n_waiting_threads = 0; typedef struct srv_conc_slot_struct srv_conc_slot_t; struct srv_conc_slot_struct{ @@ -348,9 +351,9 @@ struct srv_conc_slot_struct{ }; /* queue of threads waiting to get in */ -static UT_LIST_BASE_NODE_T(srv_conc_slot_t) srv_conc_queue; +UNIV_INTERN UT_LIST_BASE_NODE_T(srv_conc_slot_t) srv_conc_queue; /* array of wait slots */ -static srv_conc_slot_t* srv_conc_slots; +UNIV_INTERN srv_conc_slot_t* srv_conc_slots; /* Number of times a thread is allowed to enter InnoDB within the same SQL query after it has once got the ticket at srv_conc_enter_innodb */ @@ -440,8 +443,6 @@ UNIV_INTERN mysql_pfs_key_t srv_monitor_file_mutex_key; UNIV_INTERN mysql_pfs_key_t srv_dict_tmpfile_mutex_key; /* Key to register the mutex with performance schema */ UNIV_INTERN mysql_pfs_key_t srv_misc_tmpfile_mutex_key; -/* Key to register srv_sys_t::mutex with performance schema */ -UNIV_INTERN mysql_pfs_key_t srv_srv_sys_mutex_key; #endif /* UNIV_PFS_MUTEX */ /* Temporary file for innodb monitor output */ @@ -490,19 +491,6 @@ intervals. Following macros define thresholds for these conditions. */ #define SRV_RECENT_IO_ACTIVITY (PCT_IO(5)) #define SRV_PAST_IO_ACTIVITY (PCT_IO(200)) -/** Acquire the system_mutex. */ -#define srv_sys_mutex_enter() do { \ - mutex_enter(&srv_sys->mutex); \ -} while (0) - -/** Test if the system mutex is owned. */ -#define srv_sys_mutex_own() mutex_own(&srv_sys->mutex) - -/** Release the system mutex. */ -#define srv_sys_mutex_exit() do { \ - mutex_exit(&srv_sys->mutex); \ -} while (0) - /* IMPLEMENTATION OF THE SERVER MAIN PROGRAM ========================================= @@ -671,7 +659,7 @@ boosted at least to normal. This priority requirement can be seen similar to the privileged mode used when processing the kernel calls in traditional Unix.*/ -/** Thread slot in the thread table. */ +/* Thread slot in the thread table */ struct srv_slot_struct{ os_thread_id_t id; /*!< thread id */ os_thread_t handle; /*!< thread handle */ @@ -687,51 +675,12 @@ struct srv_slot_struct{ used for MySQL threads) */ }; -/** Thread slot in the thread table */ -typedef struct srv_slot_struct srv_slot_t; - -/** Thread table is an array of slots */ -typedef srv_slot_t srv_table_t; - -/** The server system */ -typedef struct srv_sys_struct srv_sys_t; - -/** The server system struct */ -struct srv_sys_struct{ - mutex_t mutex; /*!< variable protecting the - fields in this structure. */ - srv_table_t* sys_threads; /*!< server thread table */ - - UT_LIST_BASE_NODE_T(que_thr_t) - tasks; /*!< task queue */ - - ulint n_threads[SRV_MASTER + 1]; - /*!< number of system threads - in a thread class */ - - ulint n_threads_active[SRV_MASTER + 1]; - /*!< number of threads active - in a thread class */ - - srv_slot_t* waiting_threads; /*!< Array of user threads - suspended while waiting for - locks within InnoDB */ - srv_slot_t* last_slot; /*!< highest slot ever used - in the waiting_threads array */ - ulint activity_count; /*!< For tracking server - activity */ - unsigned lock_wait_timeout; /*!< TRUE if the lock monitor - thread is rolling back a - transaction that has waited - for too long for the lock a - be granted. We use this flag - to track whether the - srv_sys->mutex needs to be - acquired or not */ -}; +/* Table for MySQL threads where they will be suspended to wait for locks */ +UNIV_INTERN srv_slot_t* srv_mysql_table = NULL; UNIV_INTERN os_event_t srv_lock_timeout_thread_event; +UNIV_INTERN srv_sys_t* srv_sys = NULL; /* padding to prevent other memory update hotspots from residing on the same memory cache line */ @@ -742,8 +691,6 @@ UNIV_INTERN mutex_t* kernel_mutex_temp; the same memory cache line */ UNIV_INTERN byte srv_pad2[64]; -static srv_sys_t* srv_sys = NULL; - #if 0 /* The following three values measure the urgency of the jobs of buffer, version, and insert threads. They may vary from 0 - 1000. @@ -758,6 +705,13 @@ static ulint srv_meter_high_water2[SRV_MASTER + 1]; static ulint srv_meter_foreground[SRV_MASTER + 1]; #endif +/* The following values give info about the activity going on in +the database. They are protected by the server mutex. The arrays +are indexed by the type of the thread. */ + +UNIV_INTERN ulint srv_n_threads_active[SRV_MASTER + 1]; +UNIV_INTERN ulint srv_n_threads[SRV_MASTER + 1]; + /*********************************************************************//** Asynchronous purge thread. @return a dummy parameter */ @@ -810,15 +764,14 @@ srv_table_get_nth_slot( /*===================*/ ulint index) /*!< in: index of the slot */ { - ut_ad(srv_sys_mutex_own()); ut_a(index < OS_THREAD_MAX_N); - return(srv_sys->sys_threads + index); + return(srv_sys->threads + index); } /*********************************************************************//** Gets the number of threads in the system. -@return sum of srv_sys_t::n_threads[] */ +@return sum of srv_n_threads[] */ UNIV_INTERN ulint srv_get_n_threads(void) @@ -827,14 +780,14 @@ srv_get_n_threads(void) ulint i; ulint n_threads = 0; - srv_sys_mutex_enter(); + mutex_enter(&kernel_mutex); for (i = SRV_COM; i < SRV_MASTER + 1; i++) { - n_threads += srv_sys->n_threads[i]; + n_threads += srv_n_threads[i]; } - srv_sys_mutex_exit(); + mutex_exit(&kernel_mutex); return(n_threads); } @@ -853,8 +806,6 @@ srv_table_reserve_slot( srv_slot_t* slot; ulint i; - ut_ad(srv_sys_mutex_own()); - ut_a(type > 0); ut_a(type <= SRV_MASTER); @@ -895,7 +846,7 @@ srv_suspend_thread(void) ulint slot_no; enum srv_thread_type type; - srv_sys_mutex_enter(); + ut_ad(mutex_own(&kernel_mutex)); slot_no = thr_local_get_slot_no(os_thread_get_curr_id()); @@ -916,14 +867,12 @@ srv_suspend_thread(void) slot->suspended = TRUE; - ut_ad(srv_sys->n_threads_active[type] > 0); + ut_ad(srv_n_threads_active[type] > 0); - srv_sys->n_threads_active[type]--; + srv_n_threads_active[type]--; os_event_reset(event); - srv_sys_mutex_exit(); - return(event); } @@ -932,24 +881,23 @@ Releases threads of the type given from suspension in the thread table. NOTE! The server mutex has to be reserved by the caller! @return number of threads released: this may be less than n if not enough threads were suspended at the moment */ -static +UNIV_INTERN ulint srv_release_threads( /*================*/ enum srv_thread_type type, /*!< in: thread type */ ulint n) /*!< in: number of threads to release */ { + srv_slot_t* slot; ulint i; ulint count = 0; ut_ad(type >= SRV_WORKER); ut_ad(type <= SRV_MASTER); ut_ad(n > 0); - - srv_sys_mutex_enter(); + ut_ad(mutex_own(&kernel_mutex)); for (i = 0; i < OS_THREAD_MAX_N; i++) { - srv_slot_t* slot; slot = srv_table_get_nth_slot(i); @@ -957,7 +905,7 @@ srv_release_threads( slot->suspended = FALSE; - srv_sys->n_threads_active[type]++; + srv_n_threads_active[type]++; os_event_set(slot->event); @@ -977,8 +925,6 @@ srv_release_threads( } } - srv_sys_mutex_exit(); - return(count); } @@ -994,7 +940,7 @@ srv_get_thread_type(void) srv_slot_t* slot; enum srv_thread_type type; - srv_sys_mutex_enter(); + mutex_enter(&kernel_mutex); slot_no = thr_local_get_slot_no(os_thread_get_curr_id()); @@ -1005,7 +951,7 @@ srv_get_thread_type(void) ut_ad(type >= SRV_WORKER); ut_ad(type <= SRV_MASTER); - srv_sys_mutex_exit(); + mutex_exit(&kernel_mutex); return(type); } @@ -1017,14 +963,11 @@ void srv_init(void) /*==========*/ { - ulint i; srv_conc_slot_t* conc_slot; - ulint srv_sys_sz; + srv_slot_t* slot; + ulint i; - srv_sys_sz = sizeof(*srv_sys) - + (OS_THREAD_MAX_N * sizeof(srv_slot_t) * 2); - - srv_sys = mem_zalloc(srv_sys_sz); + srv_sys = mem_alloc(sizeof(srv_sys_t)); kernel_mutex_temp = mem_alloc(sizeof(mutex_t)); mutex_create(kernel_mutex_key, &kernel_mutex, SYNC_KERNEL); @@ -1032,29 +975,41 @@ srv_init(void) mutex_create(srv_innodb_monitor_mutex_key, &srv_innodb_monitor_mutex, SYNC_NO_ORDER_CHECK); - mutex_create(srv_srv_sys_mutex_key, &srv_sys->mutex, SYNC_THREADS); - - srv_sys_mutex_enter(); - - srv_sys->sys_threads = (srv_slot_t*) &srv_sys[1]; - srv_sys->waiting_threads = srv_sys->sys_threads + OS_THREAD_MAX_N; - srv_sys->last_slot = srv_sys->waiting_threads; + srv_sys->threads = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t)); for (i = 0; i < OS_THREAD_MAX_N; i++) { - srv_slot_t* slot; - slot = srv_table_get_nth_slot(i); - + slot->in_use = FALSE; + slot->type=0; /* Avoid purify errors */ slot->event = os_event_create(NULL); + ut_a(slot->event); + } + srv_mysql_table = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t)); + + for (i = 0; i < OS_THREAD_MAX_N; i++) { + slot = srv_mysql_table + i; + slot->in_use = FALSE; + slot->type = 0; + slot->event = os_event_create(NULL); ut_a(slot->event); } srv_lock_timeout_thread_event = os_event_create(NULL); - UT_LIST_INIT(srv_sys->tasks); + for (i = 0; i < SRV_MASTER + 1; i++) { + srv_n_threads_active[i] = 0; + srv_n_threads[i] = 0; +#if 0 + srv_meter[i] = 30; + srv_meter_low_water[i] = 50; + srv_meter_high_water[i] = 100; + srv_meter_high_water2[i] = 200; + srv_meter_foreground[i] = 250; +#endif + } - srv_sys_mutex_exit(); + UT_LIST_INIT(srv_sys->tasks); /* Create dummy indexes for infimum and supremum records */ @@ -1090,11 +1045,14 @@ srv_free(void) mem_free(srv_conc_slots); srv_conc_slots = NULL; + mem_free(srv_sys->threads); mem_free(srv_sys); srv_sys = NULL; mem_free(kernel_mutex_temp); kernel_mutex_temp = NULL; + mem_free(srv_mysql_table); + srv_mysql_table = NULL; trx_i_s_cache_free(trx_i_s_cache); } @@ -1450,150 +1408,67 @@ srv_boot(void) return(DB_SUCCESS); } -/*********************************************************************//** -Print the contents of the srv_sys_t::waiting_threads array. */ -static -void -srv_print_mysql_threads(void) -/*=========================*/ -{ - ulint i; - - for (i = 0; i < OS_THREAD_MAX_N; i++) { - srv_slot_t* slot; - - slot = srv_sys->waiting_threads + i; - - fprintf(stderr, - "Slot %lu: thread id %lu, type %lu," - " in use %lu, susp %lu, time %lu\n", - (ulong) i, - (ulong) os_thread_pf(slot->id), - (ulong) slot->type, - (ulong) slot->in_use, - (ulong) slot->suspended, - (ulong) difftime(ut_time(), slot->suspend_time)); - } -} - -/*********************************************************************//** -Release a slot in the srv_sys_t::waiting_threads. Adjust the array last pointer -if there are empty slots towards the end of the table. */ -static -void -srv_table_release_slot_for_mysql( -/*=============================*/ - srv_slot_t* slot) /*!< in: slot to release */ -{ -#ifdef UNIV_DEBUG - srv_slot_t* upper = srv_sys->waiting_threads + OS_THREAD_MAX_N; -#endif /* UNIV_DEBUG */ - - srv_sys_mutex_enter(); - - ut_a(slot->in_use); - ut_a(slot->thr != NULL); - ut_a(slot->thr->slot != NULL); - ut_a(slot->thr->slot == slot); - - /* Must be within the array boundaries. */ - ut_ad(slot >= srv_sys->waiting_threads); - ut_ad(slot < upper); - - slot->thr->slot = NULL; - slot->thr = NULL; - slot->in_use = FALSE; - - /* Scan backwards and adjust the last free slot pointer. */ - for (slot = srv_sys->last_slot; - slot > srv_sys->waiting_threads && !slot->in_use; - --slot) { - /* No op */ - } - - /* Either the array is empty or the last scanned slot is in use. */ - ut_ad(slot->in_use || slot == srv_sys->waiting_threads); - - srv_sys->last_slot = slot + 1; - - /* The last slot is either outside of the array boundry or it's - on an empty slot. */ - ut_ad(srv_sys->last_slot == upper || !srv_sys->last_slot->in_use); - - ut_ad(srv_sys->last_slot >= srv_sys->waiting_threads); - ut_ad(srv_sys->last_slot <= upper); - - srv_sys_mutex_exit(); -} - /*********************************************************************//** Reserves a slot in the thread table for the current MySQL OS thread. +NOTE! The kernel mutex has to be reserved by the caller! @return reserved slot */ static srv_slot_t* -srv_table_reserve_slot_for_mysql( -/*=============================*/ - que_thr_t* thr) /*!< in: query thread associated - with the MySQL OS thread */ +srv_table_reserve_slot_for_mysql(void) +/*==================================*/ { - ulint i; srv_slot_t* slot; + ulint i; - srv_sys_mutex_enter(); + ut_ad(mutex_own(&kernel_mutex)); - slot = srv_sys->waiting_threads; + i = 0; + slot = srv_mysql_table + i; - for (i = 0; i < OS_THREAD_MAX_N; ++i, ++slot) { - if (!slot->in_use) { - break; - } - } + while (slot->in_use) { + i++; - /* Check if we have run out of slots. */ - if (slot == srv_sys->waiting_threads+ OS_THREAD_MAX_N) { + if (i >= OS_THREAD_MAX_N) { - ut_print_timestamp(stderr); + ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: There appear to be %lu MySQL" - " threads currently waiting\n" - "InnoDB: inside InnoDB, which is the" - " upper limit. Cannot continue operation.\n" - "InnoDB: We intentionally generate" - " a seg fault to print a stack trace\n" - "InnoDB: on Linux. But first we print" - " a list of waiting threads.\n", (ulong) i); + fprintf(stderr, + " InnoDB: There appear to be %lu MySQL" + " threads currently waiting\n" + "InnoDB: inside InnoDB, which is the" + " upper limit. Cannot continue operation.\n" + "InnoDB: We intentionally generate" + " a seg fault to print a stack trace\n" + "InnoDB: on Linux. But first we print" + " a list of waiting threads.\n", (ulong) i); - srv_print_mysql_threads(); + for (i = 0; i < OS_THREAD_MAX_N; i++) { - ut_error; - } else { + slot = srv_mysql_table + i; - ut_a(slot->in_use == FALSE); + fprintf(stderr, + "Slot %lu: thread id %lu, type %lu," + " in use %lu, susp %lu, time %lu\n", + (ulong) i, + (ulong) os_thread_pf(slot->id), + (ulong) slot->type, + (ulong) slot->in_use, + (ulong) slot->suspended, + (ulong) difftime(ut_time(), + slot->suspend_time)); + } - slot->in_use = TRUE; - slot->thr = thr; - slot->thr->slot = slot; - slot->id = os_thread_get_curr_id(); - slot->handle = os_thread_get_curr(); - - if (slot->event == NULL) { - slot->event = os_event_create(NULL); - ut_a(slot->event); + ut_error; } - os_event_reset(slot->event); - slot->suspended = TRUE; - slot->suspend_time = ut_time(); + slot = srv_mysql_table + i; } - if (slot == srv_sys->last_slot) { - ++srv_sys->last_slot; - } + ut_a(slot->in_use == FALSE); - ut_ad(srv_sys->last_slot <= srv_sys->waiting_threads+ OS_THREAD_MAX_N); - - srv_sys_mutex_exit(); + slot->in_use = TRUE; + slot->id = os_thread_get_curr_id(); + slot->handle = os_thread_get_curr(); return(slot); } @@ -1612,6 +1487,7 @@ srv_suspend_mysql_thread( OS thread */ { srv_slot_t* slot; + os_event_t event; double wait_time; trx_t* trx; ulint had_dict_lock; @@ -1653,7 +1529,15 @@ srv_suspend_mysql_thread( ut_ad(thr->is_active == FALSE); - slot = srv_table_reserve_slot_for_mysql(thr); + slot = srv_table_reserve_slot_for_mysql(); + + event = slot->event; + + slot->thr = thr; + + os_event_reset(event); + + slot->suspend_time = ut_time(); if (thr->lock_state == QUE_THR_LOCK_ROW) { srv_n_lock_wait_count++; @@ -1699,7 +1583,7 @@ srv_suspend_mysql_thread( /* Suspend this thread and wait for the event. */ - os_event_wait(slot->event); + os_event_wait(event); /* After resuming, reacquire the data dictionary latch if necessary. */ @@ -1720,13 +1604,13 @@ srv_suspend_mysql_thread( srv_conc_force_enter_innodb(trx); } - wait_time = ut_difftime(ut_time(), slot->suspend_time); - mutex_enter(&kernel_mutex); /* Release the slot for others to use */ - srv_table_release_slot_for_mysql(slot); + slot->in_use = FALSE; + + wait_time = ut_difftime(ut_time(), slot->suspend_time); if (thr->lock_state == QUE_THR_LOCK_ROW) { if (ut_usectime(&sec, &ms) == -1) { @@ -1779,22 +1663,25 @@ srv_release_mysql_thread_if_suspended( que_thr_t* thr) /*!< in: query thread associated with the MySQL OS thread */ { + srv_slot_t* slot; + ulint i; + ut_ad(mutex_own(&kernel_mutex)); - if (!srv_sys->lock_wait_timeout) { - srv_sys_mutex_enter(); - } else { - ut_ad(srv_sys_mutex_own()); + for (i = 0; i < OS_THREAD_MAX_N; i++) { + + slot = srv_mysql_table + i; + + if (slot->in_use && slot->thr == thr) { + /* Found */ + + os_event_set(slot->event); + + return; + } } - if (thr->slot != NULL && thr->slot->in_use && thr->slot->thr == thr) { - - os_event_set(thr->slot->event); - } - - if (!srv_sys->lock_wait_timeout) { - srv_sys_mutex_exit(); - } + /* not found */ } /******************************************************************//** @@ -2270,95 +2157,6 @@ exit_func: OS_THREAD_DUMMY_RETURN; } -/*********************************************************************//** -Check if the thread lock wait has timed out. Release its locks if the -wait has actually timed out. */ -UNIV_INTERN -void -srv_lock_check_wait( -/*================*/ - srv_slot_t* slot) -{ - trx_t* trx; - double wait_time; - ulong lock_wait_timeout; - ib_time_t suspend_time = slot->suspend_time; - - ut_ad(srv_sys_mutex_own()); - - wait_time = ut_difftime(ut_time(), suspend_time); - - trx = thr_get_trx(slot->thr); - - lock_wait_timeout = thd_lock_wait_timeout(trx->mysql_thd); - - if (trx_is_interrupted(trx) - || (lock_wait_timeout < 100000000 - && (wait_time > (double) lock_wait_timeout - || wait_time < 0))) { - - /* Timeout exceeded or a wrap-around in system - time counter: cancel the lock request queued - by the transaction and release possible - other transactions waiting behind; it is - possible that the lock has already been - granted: in that case do nothing */ - - if (trx->wait_lock) { - trx_t* slot_trx; - - /* Release the srv_sys_t->mutex to preserve the - latch order only. */ - srv_sys_mutex_exit(); - - /* It is possible that the thread has already - freed its slot and released its locks and another - thread is now using this slot. We need to - check whether the slot is still in use by the - same thread before cancelling the wait and releasing - the locks. */ - - mutex_enter(&kernel_mutex); - - srv_sys_mutex_enter(); - - /* If the slot has been freed and is not being reused - then the slot->thr entry should be NULL. */ - if (slot->thr != NULL) { - ut_a(slot->in_use); - slot_trx = thr_get_trx(slot->thr); - } else { - ut_a(!slot->in_use); - slot_trx = NULL; - } - - /* We can't compare the pointers here because the - memory can be recycled. Transaction ids are not - recyled and therefore safe to use. We also check if - the transaction suspend time is the same that we - used for calculating the wait earlier. If the - transaction has already released its locks there - is nothing more we can do. */ - if (slot->in_use - && suspend_time == slot->suspend_time - && ut_dulint_cmp(trx->id, slot_trx->id) == 0 - && trx->wait_lock != NULL) { - - ut_a(!srv_sys->lock_wait_timeout); - ut_a(trx->que_state == TRX_QUE_LOCK_WAIT); - - srv_sys->lock_wait_timeout = TRUE; - - lock_cancel_waiting_and_release(trx->wait_lock); - - srv_sys->lock_wait_timeout = FALSE; - } - - mutex_exit(&kernel_mutex); - } - } -} - /*********************************************************************//** A thread which wakes up threads whose lock wait may have lasted too long. @return a dummy parameter */ @@ -2372,6 +2170,8 @@ srv_lock_timeout_thread( { srv_slot_t* slot; ibool some_waits; + double wait_time; + ulint i; #ifdef UNIV_PFS_THREAD pfs_register_thread(srv_lock_timeout_thread_key); @@ -2385,26 +2185,52 @@ loop: srv_lock_timeout_active = TRUE; - srv_sys_mutex_enter(); + mutex_enter(&kernel_mutex); some_waits = FALSE; - /* Check all slots for user threads that are waiting on locks, and - if they have exceeded the time limit. */ + /* Check of all slots if a thread is waiting there, and if it + has exceeded the time limit */ - for (slot = srv_sys->waiting_threads; - slot < srv_sys->last_slot; - ++slot) { + for (i = 0; i < OS_THREAD_MAX_N; i++) { + + slot = srv_mysql_table + i; if (slot->in_use) { + trx_t* trx; + ulong lock_wait_timeout; + some_waits = TRUE; - srv_lock_check_wait(slot); + + wait_time = ut_difftime(ut_time(), slot->suspend_time); + + trx = thr_get_trx(slot->thr); + lock_wait_timeout = thd_lock_wait_timeout( + trx->mysql_thd); + + if (trx_is_interrupted(trx) + || (lock_wait_timeout < 100000000 + && (wait_time > (double) lock_wait_timeout + || wait_time < 0))) { + + /* Timeout exceeded or a wrap-around in system + time counter: cancel the lock request queued + by the transaction and release possible + other transactions waiting behind; it is + possible that the lock has already been + granted: in that case do nothing */ + + if (trx->wait_lock) { + lock_cancel_waiting_and_release( + trx->wait_lock); + } + } } } os_event_reset(srv_lock_timeout_thread_event); - srv_sys_mutex_exit(); + mutex_exit(&kernel_mutex); if (srv_shutdown_state >= SRV_SHUTDOWN_CLEANUP) { goto exit_func; @@ -2549,11 +2375,11 @@ void srv_inc_activity_count_low(void) /*============================*/ { - srv_sys_mutex_enter(); + mutex_enter(&kernel_mutex); - ++srv_sys->activity_count; + ++srv_activity_count; - srv_sys_mutex_exit(); + mutex_exit(&kernel_mutex); } /******************************************************************//** @@ -2577,16 +2403,16 @@ srv_is_any_background_thread_active(void) ulint i; ibool ret = FALSE; - srv_sys_mutex_enter(); + mutex_enter(&kernel_mutex); for (i = SRV_COM; i <= SRV_MASTER; ++i) { - if (srv_sys->n_threads_active[i] != 0) { + if (srv_n_threads_active[i] != 0) { ret = TRUE; break; } } - srv_sys_mutex_exit(); + mutex_exit(&kernel_mutex); return(ret); } @@ -2603,13 +2429,16 @@ srv_active_wake_master_thread(void) /*===============================*/ { ut_ad(!mutex_own(&kernel_mutex)); - ut_ad(!srv_sys_mutex_own()); srv_inc_activity_count_low(); - if (srv_sys->n_threads_active[SRV_MASTER] == 0) { + if (srv_n_threads_active[SRV_MASTER] == 0) { + + mutex_enter(&kernel_mutex); srv_release_threads(SRV_MASTER, 1); + + mutex_exit(&kernel_mutex); } } @@ -2617,20 +2446,23 @@ srv_active_wake_master_thread(void) Tells the purge thread that there has been activity in the database and wakes up the purge thread if it is suspended (not sleeping). Note that there is a small chance that the purge thread stays suspended -(we do not protect our operation with the srv_sys_t:mutex, for -performance reasons). */ +(we do not protect our operation with the kernel mutex, for +performace reasons). */ UNIV_INTERN void srv_wake_purge_thread_if_not_active(void) /*=====================================*/ { ut_ad(!mutex_own(&kernel_mutex)); - ut_ad(!srv_sys_mutex_own()); if (srv_n_purge_threads > 0 - && srv_sys->n_threads_active[SRV_WORKER] == 0) { + && srv_n_threads_active[SRV_WORKER] == 0) { + + mutex_enter(&kernel_mutex); srv_release_threads(SRV_WORKER, 1); + + mutex_exit(&kernel_mutex); } } @@ -2641,12 +2473,13 @@ void srv_wake_master_thread(void) /*========================*/ { - ut_ad(!mutex_own(&kernel_mutex)); - ut_ad(!srv_sys_mutex_own()); + srv_activity_count++; - srv_inc_activity_count_low(); + mutex_enter(&kernel_mutex); srv_release_threads(SRV_MASTER, 1); + + mutex_exit(&kernel_mutex); } /*******************************************************************//** @@ -2657,34 +2490,17 @@ srv_wake_purge_thread(void) /*=======================*/ { ut_ad(!mutex_own(&kernel_mutex)); - ut_ad(!srv_sys_mutex_own()); if (srv_n_purge_threads > 0) { + mutex_enter(&kernel_mutex); + srv_release_threads(SRV_WORKER, 1); + + mutex_exit(&kernel_mutex); } } -/*******************************************************************//** -Check if there has been any activity. -@return FALSE if no hange in activity counter. */ -UNIV_INLINE -ibool -srv_check_activity( -/*===============*/ - ulint old_activity_count) /*!< old activity count */ -{ - ibool ret; - - srv_sys_mutex_enter(); - - ret = srv_sys->activity_count != old_activity_count; - - srv_sys_mutex_exit(); - - return(ret); -} - /********************************************************************** The master thread is tasked to ensure that flush of log file happens once every second in the background. This is to ensure that not more @@ -2771,13 +2587,13 @@ srv_master_thread( srv_main_thread_process_no = os_proc_get_number(); srv_main_thread_id = os_thread_pf(os_thread_get_curr_id()); - srv_sys_mutex_enter(); - srv_table_reserve_slot(SRV_MASTER); - srv_sys->n_threads_active[SRV_MASTER]++; + mutex_enter(&kernel_mutex); - srv_sys_mutex_exit(); + srv_n_threads_active[SRV_MASTER]++; + + mutex_exit(&kernel_mutex); loop: /*****************************************************************/ @@ -2789,13 +2605,12 @@ loop: buf_get_total_stat(&buf_stat); n_ios_very_old = log_sys->n_log_ios + buf_stat.n_pages_read + buf_stat.n_pages_written; - - srv_sys_mutex_enter(); + mutex_enter(&kernel_mutex); /* Store the user activity counter at the start of this loop */ - old_activity_count = srv_sys->activity_count; + old_activity_count = srv_activity_count; - srv_sys_mutex_exit(); + mutex_exit(&kernel_mutex); if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND) { @@ -2901,7 +2716,7 @@ loop: } } - if (srv_sys->activity_count == old_activity_count) { + if (srv_activity_count == old_activity_count) { /* There is no user activity at the moment, go to the background loop */ @@ -2992,13 +2807,18 @@ loop: srv_main_thread_op_info = "reserving kernel mutex"; + mutex_enter(&kernel_mutex); + /* ---- When there is database activity, we jump from here back to the start of loop */ - if (srv_check_activity(old_activity_count)) { + if (srv_activity_count != old_activity_count) { + mutex_exit(&kernel_mutex); goto loop; } + mutex_exit(&kernel_mutex); + /* If the database is quiet, we enter the background loop */ /*****************************************************************/ @@ -3031,9 +2851,12 @@ background_loop: srv_main_thread_op_info = "reserving kernel mutex"; - if (srv_check_activity(old_activity_count)) { + mutex_enter(&kernel_mutex); + if (srv_activity_count != old_activity_count) { + mutex_exit(&kernel_mutex); goto loop; } + mutex_exit(&kernel_mutex); srv_main_thread_op_info = "doing insert buffer merge"; @@ -3050,9 +2873,12 @@ background_loop: srv_main_thread_op_info = "reserving kernel mutex"; - if (srv_check_activity(old_activity_count)) { + mutex_enter(&kernel_mutex); + if (srv_activity_count != old_activity_count) { + mutex_exit(&kernel_mutex); goto loop; } + mutex_exit(&kernel_mutex); flush_loop: srv_main_thread_op_info = "flushing buffer pool pages"; @@ -3069,9 +2895,12 @@ flush_loop: srv_main_thread_op_info = "reserving kernel mutex"; - if (srv_check_activity(old_activity_count)) { + mutex_enter(&kernel_mutex); + if (srv_activity_count != old_activity_count) { + mutex_exit(&kernel_mutex); goto loop; } + mutex_exit(&kernel_mutex); srv_main_thread_op_info = "waiting for buffer pool flush to end"; buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); @@ -3093,10 +2922,12 @@ flush_loop: srv_main_thread_op_info = "reserving kernel mutex"; - if (srv_check_activity(old_activity_count)) { + mutex_enter(&kernel_mutex); + if (srv_activity_count != old_activity_count) { + mutex_exit(&kernel_mutex); goto loop; } - + mutex_exit(&kernel_mutex); /* srv_main_thread_op_info = "archiving log (if log archive is on)"; @@ -3142,10 +2973,10 @@ suspend_thread: goto loop; } - mutex_exit(&kernel_mutex); - event = srv_suspend_thread(); + mutex_exit(&kernel_mutex); + /* DO NOT CHANGE THIS STRING. innobase_start_or_create_for_mysql() waits for database activity to die down when converting < 4.1.x databases, and relies on this string being exactly as it is. InnoDB @@ -3195,13 +3026,13 @@ srv_purge_thread( os_thread_pf(os_thread_get_curr_id())); #endif /* UNIV_DEBUG_THREAD_CREATION */ - srv_sys_mutex_enter(); + mutex_enter(&kernel_mutex); slot_no = srv_table_reserve_slot(SRV_WORKER); - ++srv_sys->n_threads_active[SRV_WORKER]; + ++srv_n_threads_active[SRV_WORKER]; - srv_sys_mutex_exit(); + mutex_exit(&kernel_mutex); while (srv_shutdown_state != SRV_SHUTDOWN_EXIT_THREADS) { @@ -3217,8 +3048,12 @@ srv_purge_thread( os_event_t event; + mutex_enter(&kernel_mutex); + event = srv_suspend_thread(); + mutex_exit(&kernel_mutex); + os_event_wait(event); } @@ -3250,13 +3085,13 @@ srv_purge_thread( /* Free the thread local memory. */ thr_local_free(os_thread_get_curr_id()); - srv_sys_mutex_enter(); + mutex_enter(&kernel_mutex); /* Free the slot for reuse. */ slot = srv_table_get_nth_slot(slot_no); slot->in_use = FALSE; - srv_sys_mutex_exit(); + mutex_exit(&kernel_mutex); #ifdef UNIV_DEBUG_THREAD_CREATION fprintf(stderr, "InnoDB: Purge thread exiting, id %lu\n", @@ -3281,12 +3116,11 @@ srv_que_task_enqueue_low( { ut_ad(thr); - srv_sys_mutex_enter(); + mutex_enter(&kernel_mutex); UT_LIST_ADD_LAST(queue, srv_sys->tasks, thr); - srv_sys_mutex_exit(); - srv_release_threads(SRV_WORKER, 1); -} + mutex_exit(&kernel_mutex); +} diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 9e169c7c27e..235f733382d 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -1167,7 +1167,6 @@ sync_thread_add_level( case SYNC_SEARCH_SYS_CONF: case SYNC_TRX_LOCK_HEAP: case SYNC_KERNEL: - case SYNC_THREADS: case SYNC_IBUF_BITMAP_MUTEX: case SYNC_RSEG: case SYNC_TRX_UNDO: diff --git a/storage/innobase/trx/trx0roll.c b/storage/innobase/trx/trx0roll.c index 4f1a71a5531..6e72b13e116 100644 --- a/storage/innobase/trx/trx0roll.c +++ b/storage/innobase/trx/trx0roll.c @@ -37,6 +37,7 @@ Created 3/26/1996 Heikki Tuuri #include "trx0rec.h" #include "que0que.h" #include "usr0sess.h" +#include "srv0que.h" #include "srv0start.h" #include "row0undo.h" #include "row0mysql.h"