diff options
Diffstat (limited to 'storage/innobase/srv/srv0srv.cc')
-rw-r--r-- | storage/innobase/srv/srv0srv.cc | 882 |
1 files changed, 379 insertions, 503 deletions
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 337460fc4d2..2e9f5a0eff8 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -40,9 +40,6 @@ Created 10/8/1995 Heikki Tuuri *******************************************************/ #include "my_global.h" -// JAN: TODO: MySQL 5.7 missing header -//#include "my_thread.h" -// #include "mysql/psi/mysql_stage.h" #include "mysql/psi/psi.h" @@ -62,7 +59,6 @@ Created 10/8/1995 Heikki Tuuri #include "srv0mon.h" #include "srv0srv.h" #include "srv0start.h" -#include "sync0sync.h" #include "trx0i_s.h" #include "trx0purge.h" #include "ut0crc32.h" @@ -75,9 +71,11 @@ Created 10/8/1995 Heikki Tuuri #include <list> #include "log.h" +#include "transactional_lock_guard.h" + #include <my_service_manager.h> /* The following is the maximum allowed duration of a lock wait. */ -UNIV_INTERN ulong srv_fatal_semaphore_wait_threshold = DEFAULT_SRV_FATAL_SEMAPHORE_TIMEOUT; +ulong srv_fatal_semaphore_wait_threshold = DEFAULT_SRV_FATAL_SEMAPHORE_TIMEOUT; /* How much data manipulation language (DML) statements need to be delayed, in microseconds, in order to reduce the lagging of the purge thread. */ @@ -185,7 +183,7 @@ mutex before switching to blocking wait on the mutex */ /** Check whether the number of failed nonblocking mutex acquisition attempts exceeds maximum allowed value. If so, srv_printf_innodb_monitor() will request mutex acquisition -with mutex_enter(), which will wait until it gets the mutex. */ +with mysql_mutex_lock(), which will wait until it gets the mutex. */ #define MUTEX_NOWAIT(mutex_skipped) ((mutex_skipped) < MAX_MUTEX_NOWAIT) /** copy of innodb_buffer_pool_size */ @@ -212,6 +210,9 @@ ulong srv_buf_pool_load_pages_abort = LONG_MAX; /** Lock table size in bytes */ ulint srv_lock_table_size = ULINT_MAX; +/** the value of innodb_checksum_algorithm */ +ulong srv_checksum_algorithm; + /** innodb_read_io_threads */ uint srv_n_read_io_threads; /** innodb_write_io_threads */ @@ -346,22 +347,25 @@ ulint srv_truncated_status_writes; ulong srv_available_undo_logs; /* Defragmentation */ -UNIV_INTERN my_bool srv_defragment; +my_bool srv_defragment; /** innodb_defragment_n_pages */ -UNIV_INTERN uint srv_defragment_n_pages; -UNIV_INTERN uint srv_defragment_stats_accuracy; +uint srv_defragment_n_pages; +uint srv_defragment_stats_accuracy; /** innodb_defragment_fill_factor_n_recs */ -UNIV_INTERN uint srv_defragment_fill_factor_n_recs; +uint srv_defragment_fill_factor_n_recs; /** innodb_defragment_fill_factor */ -UNIV_INTERN double srv_defragment_fill_factor; +double srv_defragment_fill_factor; /** innodb_defragment_frequency */ -UNIV_INTERN uint srv_defragment_frequency; +uint srv_defragment_frequency; /** derived from innodb_defragment_frequency; @see innodb_defragment_frequency_update() */ -UNIV_INTERN ulonglong srv_defragment_interval; +ulonglong srv_defragment_interval; /** Current mode of operation */ -UNIV_INTERN enum srv_operation_mode srv_operation; +enum srv_operation_mode srv_operation; + +/** whether this is the server's first start after mariabackup --prepare */ +bool srv_start_after_restore; /* Set the following to 0 if you want InnoDB to write messages on stderr on startup/shutdown. Not enabled on the embedded server. */ @@ -379,20 +383,18 @@ my_bool srv_immediate_scrub_data_uncompressed; static time_t srv_last_monitor_time; -static ib_mutex_t srv_innodb_monitor_mutex; +static mysql_mutex_t srv_innodb_monitor_mutex; /** Mutex protecting page_zip_stat_per_index */ -ib_mutex_t page_zip_stat_per_index_mutex; +mysql_mutex_t page_zip_stat_per_index_mutex; -/* Mutex for locking srv_monitor_file. Not created if srv_read_only_mode */ -ib_mutex_t srv_monitor_file_mutex; +/** Mutex for locking srv_monitor_file */ +mysql_mutex_t srv_monitor_file_mutex; /** Temporary file for innodb monitor output */ FILE* srv_monitor_file; -/** Mutex for locking srv_misc_tmpfile. Not created if srv_read_only_mode. -This mutex has a very low rank; threads reserving it should not -acquire any further latches or sleep before releasing this one. */ -ib_mutex_t srv_misc_tmpfile_mutex; +/** Mutex for locking srv_misc_tmpfile */ +mysql_mutex_t srv_misc_tmpfile_mutex; /** Temporary file for miscellanous diagnostic output */ FILE* srv_misc_tmpfile; @@ -414,7 +416,7 @@ second. */ static time_t srv_last_log_flush_time; /** Buffer pool dump status frequence in percentages */ -UNIV_INTERN ulong srv_buf_dump_status_frequency; +ulong srv_buf_dump_status_frequency; /* IMPLEMENTATION OF THE SERVER MAIN PROGRAM @@ -434,19 +436,13 @@ lock -- semaphore; kernel -- kernel; query thread execution: -(a) without lock mutex +(a) without lock_sys.latch reserved -- process executing in user mode; -(b) with lock mutex reserved +(b) with lock_sys.latch reserved -- process executing in kernel mode; -The server has several backgroind threads all running at the same -priority as user threads. It periodically checks if here is anything -happening in the server which requires intervention of the master -thread. Such situations may be, for example, when flushing of dirty -blocks is needed in the buffer pool or old version of database rows -have to be cleaned away (purged). The user can configure a separate -dedicated purge thread(s) too, in which case the master thread does not -do any purging. +The server has several background threads all running at the same +priority as user threads. The threads which we call user threads serve the queries of the MySQL server. They run at normal priority. @@ -468,7 +464,7 @@ priority of the background thread so that it will be scheduled and it can release the resource. This solution is called priority inheritance in real-time programming. A drawback of this solution is that the overhead of acquiring a mutex increases slightly, maybe 0.2 microseconds on a 100 -MHz Pentium, because the thread has to call os_thread_get_curr_id. This may +MHz Pentium, because the thread has to call pthread_self. This may be compared to 0.5 microsecond overhead for a mutex lock-unlock pair. Note that the thread cannot store the information in the resource , say mutex, itself, because competing threads could wipe out the information if it is @@ -490,7 +486,7 @@ in a traditional Unix implementation. */ /** The server system struct */ struct srv_sys_t{ - ib_mutex_t tasks_mutex; /*!< variable protecting the + mysql_mutex_t tasks_mutex; /*!< variable protecting the tasks queue */ UT_LIST_BASE_NODE_T(que_thr_t) tasks; /*!< task queue */ @@ -510,8 +506,28 @@ static srv_sys_t srv_sys; struct purge_coordinator_state { /** Snapshot of the last history length before the purge call.*/ - size_t m_history_length= 0; - Atomic_counter<int> m_running{0}; + size_t m_history_length; + Atomic_counter<int> m_running; +private: + ulint count; + ulint n_use_threads; + ulint n_threads; + + ulint lsn_lwm; + ulint lsn_hwm; + ulonglong start_time; + ulint lsn_age_factor; + + static constexpr ulint adaptive_purge_threshold= 20; + static constexpr ulint safety_net= 20; + ulint series[innodb_purge_threads_MAX + 1]; + + inline void compute_series(); + inline void lazy_init(); + void refresh(bool full); + +public: + inline void do_purge(); }; static purge_coordinator_state purge_state; @@ -593,13 +609,6 @@ static void thread_pool_thread_end() } -#ifndef DBUG_OFF -static void dbug_after_task_callback() -{ - ut_ad(!sync_check_iterate(sync_check())); -} -#endif - void srv_thread_pool_init() { DBUG_ASSERT(!srv_thread_pool); @@ -611,9 +620,6 @@ void srv_thread_pool_init() #endif srv_thread_pool->set_thread_callbacks(thread_pool_thread_init, thread_pool_thread_end); -#ifndef DBUG_OFF - tpool::set_after_task_callback(dbug_after_task_callback); -#endif } @@ -629,25 +635,15 @@ static bool need_srv_free; /** Initialize the server. */ static void srv_init() { - mutex_create(LATCH_ID_SRV_INNODB_MONITOR, &srv_innodb_monitor_mutex); - - if (!srv_read_only_mode) { - mutex_create(LATCH_ID_SRV_SYS_TASKS, &srv_sys.tasks_mutex); - - UT_LIST_INIT(srv_sys.tasks, &que_thr_t::queue); - } + mysql_mutex_init(srv_innodb_monitor_mutex_key, + &srv_innodb_monitor_mutex, nullptr); + mysql_mutex_init(srv_threads_mutex_key, &srv_sys.tasks_mutex, nullptr); + UT_LIST_INIT(srv_sys.tasks, &que_thr_t::queue); need_srv_free = true; - /* page_zip_stat_per_index_mutex is acquired from: - 1. page_zip_compress() (after SYNC_FSP) - 2. page_zip_decompress() - 3. i_s_cmp_per_index_fill_low() (where SYNC_DICT is acquired) - 4. innodb_cmp_per_index_update(), no other latches - since we do not acquire any other latches while holding this mutex, - it can have very low level. We pick SYNC_ANY_LATCH for it. */ - mutex_create(LATCH_ID_PAGE_ZIP_STAT_PER_INDEX, - &page_zip_stat_per_index_mutex); + mysql_mutex_init(page_zip_stat_per_index_mutex_key, + &page_zip_stat_per_index_mutex, nullptr); /* Initialize some INFORMATION SCHEMA internal structures */ trx_i_s_cache_init(trx_i_s_cache); @@ -663,12 +659,9 @@ srv_free(void) return; } - mutex_free(&srv_innodb_monitor_mutex); - mutex_free(&page_zip_stat_per_index_mutex); - - if (!srv_read_only_mode) { - mutex_free(&srv_sys.tasks_mutex); - } + mysql_mutex_destroy(&srv_innodb_monitor_mutex); + mysql_mutex_destroy(&page_zip_stat_per_index_mutex); + mysql_mutex_destroy(&srv_sys.tasks_mutex); trx_i_s_cache_free(trx_i_s_cache); srv_thread_pool_end(); @@ -676,27 +669,28 @@ srv_free(void) /*********************************************************************//** Boots the InnoDB server. */ -void -srv_boot(void) -/*==========*/ +void srv_boot() { - srv_thread_pool_init(); - sync_check_init(); - trx_pool_init(); - row_mysql_init(); - srv_init(); +#ifndef NO_ELISION + if (transactional_lock_enabled()) + sql_print_information("InnoDB: Using transactional memory"); +#endif + buf_dblwr.init(); + srv_thread_pool_init(); + trx_pool_init(); + srv_init(); } /******************************************************************//** Refreshes the values used to calculate per-second averages. */ static void srv_refresh_innodb_monitor_stats(time_t current_time) { - mutex_enter(&srv_innodb_monitor_mutex); + mysql_mutex_lock(&srv_innodb_monitor_mutex); if (difftime(current_time, srv_last_monitor_time) < 60) { /* We referesh InnoDB Monitor values so that averages are printed from at most 60 last seconds */ - mutex_exit(&srv_innodb_monitor_mutex); + mysql_mutex_unlock(&srv_innodb_monitor_mutex); return; } @@ -706,8 +700,8 @@ static void srv_refresh_innodb_monitor_stats(time_t current_time) #ifdef BTR_CUR_HASH_ADAPT btr_cur_n_sea_old = btr_cur_n_sea; -#endif /* BTR_CUR_HASH_ADAPT */ btr_cur_n_non_sea_old = btr_cur_n_non_sea; +#endif /* BTR_CUR_HASH_ADAPT */ log_refresh_stats(); @@ -723,7 +717,7 @@ static void srv_refresh_innodb_monitor_stats(time_t current_time) srv_n_system_rows_deleted_old = srv_stats.n_system_rows_deleted; srv_n_system_rows_read_old = srv_stats.n_system_rows_read; - mutex_exit(&srv_innodb_monitor_mutex); + mysql_mutex_unlock(&srv_innodb_monitor_mutex); } /******************************************************************//** @@ -734,8 +728,7 @@ ibool srv_printf_innodb_monitor( /*======================*/ FILE* file, /*!< in: output stream */ - ibool nowait, /*!< in: whether to wait for the - lock_sys_t:: mutex */ + ibool nowait, /*!< in: whether to wait for lock_sys.latch */ ulint* trx_start_pos, /*!< out: file position of the start of the list of active transactions */ ulint* trx_end) /*!< out: file position of the end of @@ -745,7 +738,7 @@ srv_printf_innodb_monitor( time_t current_time; ibool ret; - mutex_enter(&srv_innodb_monitor_mutex); + mysql_mutex_lock(&srv_innodb_monitor_mutex); current_time = time(NULL); @@ -772,18 +765,18 @@ srv_printf_innodb_monitor( "-----------------\n", file); srv_print_master_thread_info(file); + /* This section is intentionally left blank, for tools like "innotop" */ fputs("----------\n" "SEMAPHORES\n" "----------\n", file); - - sync_print(file); + /* End of intentionally blank section */ /* Conceptually, srv_innodb_monitor_mutex has a very high latching - order level in sync0sync.h, while dict_foreign_err_mutex has a very - low level 135. Therefore we can reserve the latter mutex here without + order level, while dict_foreign_err_mutex has a very low level. + Therefore we can reserve the latter mutex here without a danger of a deadlock of threads. */ - mutex_enter(&dict_foreign_err_mutex); + mysql_mutex_lock(&dict_foreign_err_mutex); if (!srv_read_only_mode && ftell(dict_foreign_err_file) != 0L) { fputs("------------------------\n" @@ -792,12 +785,12 @@ srv_printf_innodb_monitor( ut_copy_file(file, dict_foreign_err_file); } - mutex_exit(&dict_foreign_err_mutex); + mysql_mutex_unlock(&dict_foreign_err_mutex); /* Only if lock_print_info_summary proceeds correctly, before we call the lock_print_info_all_transactions to print all the lock information. IMPORTANT NOTE: This - function acquires the lock mutex on success. */ + function acquires exclusive lock_sys.latch on success. */ ret = lock_print_info_summary(file, nowait); if (ret) { @@ -810,9 +803,8 @@ srv_printf_innodb_monitor( } } - /* NOTE: If we get here then we have the lock mutex. This - function will release the lock mutex that we acquired when - we called the lock_print_info_summary() function earlier. */ + /* NOTE: The following function will release the lock_sys.latch + that lock_print_info_summary() acquired. */ lock_print_info_all_transactions(file); @@ -839,29 +831,27 @@ srv_printf_innodb_monitor( #ifdef BTR_CUR_HASH_ADAPT for (ulint i = 0; i < btr_ahi_parts && btr_search_enabled; ++i) { const auto part= &btr_search_sys.parts[i]; - rw_lock_s_lock(&part->latch); + part->latch.rd_lock(SRW_LOCK_CALL); ut_ad(part->heap->type == MEM_HEAP_FOR_BTR_SEARCH); fprintf(file, "Hash table size " ULINTPF ", node heap has " ULINTPF " buffer(s)\n", part->table.n_cells, part->heap->base.count - !part->heap->free_block); - rw_lock_s_unlock(&part->latch); + part->latch.rd_unlock(); } + /* btr_cur_n_sea_old and btr_cur_n_non_sea_old are protected by + srv_innodb_monitor_mutex (srv_refresh_innodb_monitor_stats) */ + const ulint with_ahi = btr_cur_n_sea, without_ahi = btr_cur_n_non_sea; fprintf(file, "%.2f hash searches/s, %.2f non-hash searches/s\n", - static_cast<double>(btr_cur_n_sea - btr_cur_n_sea_old) + static_cast<double>(with_ahi - btr_cur_n_sea_old) / time_elapsed, - static_cast<double>(btr_cur_n_non_sea - btr_cur_n_non_sea_old) - / time_elapsed); - btr_cur_n_sea_old = btr_cur_n_sea; -#else /* BTR_CUR_HASH_ADAPT */ - fprintf(file, - "%.2f non-hash searches/s\n", - static_cast<double>(btr_cur_n_non_sea - btr_cur_n_non_sea_old) + static_cast<double>(without_ahi - btr_cur_n_non_sea_old) / time_elapsed); + btr_cur_n_sea_old = with_ahi; + btr_cur_n_non_sea_old = without_ahi; #endif /* BTR_CUR_HASH_ADAPT */ - btr_cur_n_non_sea_old = btr_cur_n_non_sea; fputs("---\n" "LOG\n" @@ -953,7 +943,7 @@ srv_printf_innodb_monitor( fputs("----------------------------\n" "END OF INNODB MONITOR OUTPUT\n" "============================\n", file); - mutex_exit(&srv_innodb_monitor_mutex); + mysql_mutex_unlock(&srv_innodb_monitor_mutex); fflush(file); return(ret); @@ -972,24 +962,27 @@ srv_export_innodb_status(void) } #ifdef BTR_CUR_HASH_ADAPT + export_vars.innodb_ahi_hit = btr_cur_n_sea; + export_vars.innodb_ahi_miss = btr_cur_n_non_sea; + ulint mem_adaptive_hash = 0; for (ulong i = 0; i < btr_ahi_parts; i++) { const auto part= &btr_search_sys.parts[i]; - rw_lock_s_lock(&part->latch); + part->latch.rd_lock(SRW_LOCK_CALL); if (part->heap) { ut_ad(part->heap->type == MEM_HEAP_FOR_BTR_SEARCH); mem_adaptive_hash += mem_heap_get_size(part->heap) + part->table.n_cells * sizeof(hash_cell_t); } - rw_lock_s_unlock(&part->latch); + part->latch.rd_unlock(); } export_vars.innodb_mem_adaptive_hash = mem_adaptive_hash; #endif export_vars.innodb_mem_dictionary = dict_sys.rough_size(); - mutex_enter(&srv_innodb_monitor_mutex); + mysql_mutex_lock(&srv_innodb_monitor_mutex); export_vars.innodb_data_pending_reads = ulint(MONITOR_VALUE(MONITOR_OS_PENDING_READS)); @@ -1009,59 +1002,22 @@ srv_export_innodb_status(void) export_vars.innodb_data_writes = os_n_file_writes; - ulint dblwr = 0; - - if (buf_dblwr.is_initialised()) { - buf_dblwr.lock(); - dblwr = buf_dblwr.submitted(); - export_vars.innodb_dblwr_pages_written = buf_dblwr.written(); - export_vars.innodb_dblwr_writes = buf_dblwr.batches(); - buf_dblwr.unlock(); - } + buf_dblwr.lock(); + ulint dblwr = buf_dblwr.submitted(); + export_vars.innodb_dblwr_pages_written = buf_dblwr.written(); + export_vars.innodb_dblwr_writes = buf_dblwr.batches(); + buf_dblwr.unlock(); export_vars.innodb_data_written = srv_stats.data_written + dblwr; - export_vars.innodb_buffer_pool_read_requests - = buf_pool.stat.n_page_gets; - export_vars.innodb_buffer_pool_write_requests = srv_stats.buf_pool_write_requests; - export_vars.innodb_buffer_pool_reads = srv_stats.buf_pool_reads; - - export_vars.innodb_buffer_pool_read_ahead_rnd = - buf_pool.stat.n_ra_pages_read_rnd; - - export_vars.innodb_buffer_pool_read_ahead = - buf_pool.stat.n_ra_pages_read; - - export_vars.innodb_buffer_pool_read_ahead_evicted = - buf_pool.stat.n_ra_pages_evicted; - - export_vars.innodb_buffer_pool_pages_data = - UT_LIST_GET_LEN(buf_pool.LRU); - export_vars.innodb_buffer_pool_bytes_data = buf_pool.stat.LRU_bytes + (UT_LIST_GET_LEN(buf_pool.unzip_LRU) << srv_page_size_shift); - export_vars.innodb_buffer_pool_pages_dirty = - UT_LIST_GET_LEN(buf_pool.flush_list); - - export_vars.innodb_buffer_pool_pages_made_young - = buf_pool.stat.n_pages_made_young; - export_vars.innodb_buffer_pool_pages_made_not_young - = buf_pool.stat.n_pages_not_made_young; - - export_vars.innodb_buffer_pool_pages_old = buf_pool.LRU_old_len; - - export_vars.innodb_buffer_pool_bytes_dirty = - buf_pool.stat.flush_list_bytes; - - export_vars.innodb_buffer_pool_pages_free = - UT_LIST_GET_LEN(buf_pool.free); - #ifdef UNIV_DEBUG export_vars.innodb_buffer_pool_pages_latched = buf_get_latched_pages_number(); @@ -1074,7 +1030,7 @@ srv_export_innodb_status(void) - UT_LIST_GET_LEN(buf_pool.free); export_vars.innodb_max_trx_id = trx_sys.get_max_trx_id(); - export_vars.innodb_history_list_length = trx_sys.rseg_history_len; + export_vars.innodb_history_list_length = trx_sys.history_size_approx(); export_vars.innodb_log_waits = srv_stats.log_waits; @@ -1092,25 +1048,21 @@ srv_export_innodb_status(void) export_vars.innodb_log_writes = srv_stats.log_writes; - export_vars.innodb_row_lock_waits = srv_stats.n_lock_wait_count; - - export_vars.innodb_row_lock_current_waits = - srv_stats.n_lock_wait_current_count; + mysql_mutex_lock(&lock_sys.wait_mutex); + export_vars.innodb_row_lock_waits = lock_sys.get_wait_cumulative(); - export_vars.innodb_row_lock_time = srv_stats.n_lock_wait_time / 1000; + export_vars.innodb_row_lock_current_waits= lock_sys.get_wait_pending(); - if (srv_stats.n_lock_wait_count > 0) { - - export_vars.innodb_row_lock_time_avg = (ulint) - (srv_stats.n_lock_wait_time - / 1000 / srv_stats.n_lock_wait_count); - - } else { - export_vars.innodb_row_lock_time_avg = 0; - } + export_vars.innodb_row_lock_time = lock_sys.get_wait_time_cumulative() + / 1000; + export_vars.innodb_row_lock_time_max = lock_sys.get_wait_time_max() + / 1000; + mysql_mutex_unlock(&lock_sys.wait_mutex); - export_vars.innodb_row_lock_time_max = - lock_sys.n_lock_max_wait_time / 1000; + export_vars.innodb_row_lock_time_avg= export_vars.innodb_row_lock_waits + ? static_cast<ulint>(export_vars.innodb_row_lock_time + / export_vars.innodb_row_lock_waits) + : 0; export_vars.innodb_rows_read = srv_stats.n_rows_read; @@ -1181,7 +1133,7 @@ srv_export_innodb_status(void) srv_stats.n_key_requests; } - mutex_exit(&srv_innodb_monitor_mutex); + mysql_mutex_unlock(&srv_innodb_monitor_mutex); mysql_mutex_lock(&log_sys.mutex); export_vars.innodb_lsn_current = log_sys.get_lsn(); @@ -1221,7 +1173,7 @@ static void srv_monitor() if (srv_print_innodb_monitor) { /* Reset mutex_skipped counter everytime srv_print_innodb_monitor changes. This is to - ensure we will not be blocked by lock_sys.mutex + ensure we will not be blocked by lock_sys.latch for short duration information printing */ if (!monitor_state.last_srv_print_monitor) { monitor_state.mutex_skipped = 0; @@ -1245,7 +1197,7 @@ static void srv_monitor() mutexes in read-only-mode */ if (!srv_read_only_mode && srv_innodb_status) { - mutex_enter(&srv_monitor_file_mutex); + mysql_mutex_lock(&srv_monitor_file_mutex); rewind(srv_monitor_file); if (!srv_printf_innodb_monitor(srv_monitor_file, MUTEX_NOWAIT(monitor_state.mutex_skipped), @@ -1256,28 +1208,18 @@ static void srv_monitor() } os_file_set_eof(srv_monitor_file); - mutex_exit(&srv_monitor_file_mutex); + mysql_mutex_unlock(&srv_monitor_file_mutex); } } srv_refresh_innodb_monitor_stats(current_time); } -/*********************************************************************//** -A task which prints warnings about semaphore waits which have lasted -too long. These can be used to track bugs which cause hangs. -*/ +/** Periodic task which prints the info output by various InnoDB monitors.*/ void srv_monitor_task(void*) { /* number of successive fatal timeouts observed */ - static ulint fatal_cnt; static lsn_t old_lsn = recv_sys.recovered_lsn; - /* longest waiting thread for a semaphore */ - os_thread_id_t waiter; - static os_thread_id_t old_waiter = os_thread_get_curr_id(); - /* the semaphore that is being waited for */ - const void* sema = NULL; - static const void* old_sema = NULL; ut_ad(!srv_read_only_mode); @@ -1292,18 +1234,24 @@ void srv_monitor_task(void*) eviction policy. */ buf_LRU_stat_update(); - if (sync_array_print_long_waits(&waiter, &sema) - && sema == old_sema && os_thread_eq(waiter, old_waiter)) { - if (fatal_cnt++) { - ib::fatal() << "Semaphore wait has lasted > " - << srv_fatal_semaphore_wait_threshold - << " seconds. We intentionally crash the" - " server because it appears to be hung."; + ulonglong now = my_hrtime_coarse().val; + const ulong threshold = srv_fatal_semaphore_wait_threshold; + + if (ulonglong start = dict_sys.oldest_wait()) { + if (now >= start) { + now -= start; + ulong waited = static_cast<ulong>(now / 1000000); + if (waited >= threshold) { + ib::fatal() << dict_sys.fatal_msg; + } + + if (waited == threshold / 4 + || waited == threshold / 2 + || waited == threshold / 4 * 3) { + ib::warn() << "Long wait (" << waited + << " seconds) for dict_sys.latch"; + } } - } else { - fatal_cnt = 0; - old_waiter = waiter; - old_sema = sema; } srv_monitor(); @@ -1333,7 +1281,6 @@ bool srv_any_background_activity() static void purge_worker_callback(void*); static void purge_coordinator_callback(void*); -static void purge_coordinator_timer_callback(void*); static tpool::task_group purge_task_group; tpool::waitable_task purge_worker_task(purge_worker_callback, nullptr, @@ -1351,7 +1298,7 @@ srv_wake_purge_thread_if_not_active() ut_ad(!srv_read_only_mode); if (purge_sys.enabled() && !purge_sys.paused() - && trx_sys.rseg_history_len) { + && trx_sys.history_exists()) { if(++purge_state.m_running == 1) { srv_thread_pool->submit_task(&purge_coordinator_task); } @@ -1364,24 +1311,41 @@ bool purge_sys_t::running() const return purge_coordinator_task.is_running(); } +/** Suspend purge in data dictionary tables */ +void purge_sys_t::stop_SYS() +{ + latch.rd_lock(SRW_LOCK_CALL); + ++m_SYS_paused; + latch.rd_unlock(); +} + /** Stop purge during FLUSH TABLES FOR EXPORT */ void purge_sys_t::stop() { - rw_lock_x_lock(&latch); - - if (!enabled()) + for (;;) { - /* Shutdown must have been initiated during FLUSH TABLES FOR EXPORT. */ - ut_ad(!srv_undo_sources); - rw_lock_x_unlock(&latch); - return; - } + latch.wr_lock(SRW_LOCK_CALL); - ut_ad(srv_n_purge_threads > 0); + if (!enabled()) + { + /* Shutdown must have been initiated during FLUSH TABLES FOR EXPORT. */ + ut_ad(!srv_undo_sources); + latch.wr_unlock(); + return; + } + + ut_ad(srv_n_purge_threads > 0); + + if (!must_wait_SYS()) + break; + + latch.wr_unlock(); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } const auto paused= m_paused++; - rw_lock_x_unlock(&latch); + latch.wr_unlock(); if (!paused) { @@ -1391,6 +1355,14 @@ void purge_sys_t::stop() } } +/** Resume purge in data dictionary tables */ +void purge_sys_t::resume_SYS(void *) +{ + ut_d(const auto s=) + purge_sys.m_SYS_paused--; + ut_ad(s); +} + /** Resume purge at UNLOCK TABLES after FLUSH TABLES FOR EXPORT */ void purge_sys_t::resume() { @@ -1402,9 +1374,8 @@ void purge_sys_t::resume() } ut_ad(!srv_read_only_mode); ut_ad(srv_force_recovery < SRV_FORCE_NO_BACKGROUND); - ut_ad(!sync_check_iterate(sync_check())); purge_coordinator_task.enable(); - rw_lock_x_lock(&latch); + latch.wr_lock(SRW_LOCK_CALL); int32_t paused= m_paused--; ut_a(paused); @@ -1415,7 +1386,7 @@ void purge_sys_t::resume() srv_wake_purge_thread_if_not_active(); MONITOR_ATOMIC_INC(MONITOR_PURGE_RESUME_COUNT); } - rw_lock_x_unlock(&latch); + latch.wr_unlock(); } /*******************************************************************//** @@ -1448,10 +1419,7 @@ 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 than one second of trxs are lost in case of crash when innodb_flush_logs_at_trx_commit != 1 */ -static -void -srv_sync_log_buffer_in_background(void) -/*===================================*/ +static void srv_sync_log_buffer_in_background() { time_t current_time = time(NULL); @@ -1464,50 +1432,16 @@ srv_sync_log_buffer_in_background(void) } } -/********************************************************************//** -Make room in the table cache by evicting an unused table. -@return number of tables evicted. */ -static -ulint -srv_master_evict_from_table_cache( -/*==============================*/ - ulint pct_check) /*!< in: max percent to check */ -{ - ulint n_tables_evicted = 0; - - dict_sys_lock(); - - n_tables_evicted = dict_make_room_in_cache( - innobase_get_table_cache_size(), pct_check); - - dict_sys_unlock(); - - return(n_tables_evicted); -} - /** Report progress during shutdown. @param last time of last output -@param n_drop number of tables to be dropped @param n_read number of page reads initiated for change buffer merge */ -static void srv_shutdown_print(time_t &last, ulint n_drop, ulint n_read) +static void srv_shutdown_print(time_t &last, ulint n_read) { time_t now= time(nullptr); if (now - last >= 15) { last= now; - if (n_drop) - { - sql_print_information("InnoDB: Waiting for %zu table(s) to be dropped", - n_drop); -#if defined HAVE_SYSTEMD && !defined EMBEDDED_LIBRARY - service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, - "InnoDB: Waiting for %zu table(s)" - " to be dropped", n_drop); -#endif - return; - } - const ulint ibuf_size= ibuf.size; sql_print_information("Completing change buffer merge;" " %zu page reads initiated;" @@ -1523,124 +1457,41 @@ static void srv_shutdown_print(time_t &last, ulint n_drop, ulint n_read) } } -/*********************************************************************//** -Perform the tasks that the master thread is supposed to do when the -server is active. There are two types of tasks. The first category is -of such tasks which are performed at each inovcation of this function. -We assume that this function is called roughly every second when the -server is active. The second category is of such tasks which are -performed at some interval e.g.: purge, dict_LRU cleanup etc. */ -static -void -srv_master_do_active_tasks(void) -/*============================*/ +/** Perform periodic tasks whenever the server is active. +@param counter_time microsecond_interval_timer() */ +static void srv_master_do_active_tasks(ulonglong counter_time) { - time_t cur_time = time(NULL); - ulonglong counter_time = microsecond_interval_timer(); - - /* First do the tasks that we are suppose to do at each - invocation of this function. */ - ++srv_main_active_loops; MONITOR_INC(MONITOR_MASTER_ACTIVE_LOOPS); - /* ALTER TABLE in MySQL requires on Unix that the table handler - can drop tables lazily after there no longer are SELECT - queries to them. */ - srv_main_thread_op_info = "doing background drop tables"; - row_drop_tables_for_mysql_in_background(); - MONITOR_INC_TIME_IN_MICRO_SECS( - MONITOR_SRV_BACKGROUND_DROP_TABLE_MICROSECOND, counter_time); - - if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { - return; - } - - /* make sure that there is enough reusable space in the redo - log files */ - srv_main_thread_op_info = "checking free log space"; - log_free_check(); - - /* Flush logs if needed */ - srv_main_thread_op_info = "flushing log"; - srv_sync_log_buffer_in_background(); - MONITOR_INC_TIME_IN_MICRO_SECS( - MONITOR_SRV_LOG_FLUSH_MICROSECOND, counter_time); - - /* Now see if various tasks that are performed at defined - intervals need to be performed. */ - - if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { - return; - } - - if (!(cur_time % 47)) { + if (!(counter_time % (47 * 1000000ULL))) { srv_main_thread_op_info = "enforcing dict cache limit"; - ulint n_evicted = srv_master_evict_from_table_cache(50); - if (n_evicted != 0) { + if (ulint n_evicted = dict_sys.evict_table_LRU(true)) { MONITOR_INC_VALUE( - MONITOR_SRV_DICT_LRU_EVICT_COUNT_ACTIVE, n_evicted); + MONITOR_SRV_DICT_LRU_EVICT_COUNT_ACTIVE, + n_evicted); } MONITOR_INC_TIME_IN_MICRO_SECS( MONITOR_SRV_DICT_LRU_MICROSECOND, counter_time); } } -/*********************************************************************//** -Perform the tasks that the master thread is supposed to do whenever the -server is idle. We do check for the server state during this function -and if the server has entered the shutdown phase we may return from -the function without completing the required tasks. -Note that the server can move to active state when we are executing this -function but we don't check for that as we are suppose to perform more -or less same tasks when server is active. */ -static -void -srv_master_do_idle_tasks(void) -/*==========================*/ +/** Perform periodic tasks whenever the server is idle. +@param counter_time microsecond_interval_timer() */ +static void srv_master_do_idle_tasks(ulonglong counter_time) { ++srv_main_idle_loops; MONITOR_INC(MONITOR_MASTER_IDLE_LOOPS); - - /* ALTER TABLE in MySQL requires on Unix that the table handler - can drop tables lazily after there no longer are SELECT - queries to them. */ - ulonglong counter_time = microsecond_interval_timer(); - srv_main_thread_op_info = "doing background drop tables"; - row_drop_tables_for_mysql_in_background(); - MONITOR_INC_TIME_IN_MICRO_SECS( - MONITOR_SRV_BACKGROUND_DROP_TABLE_MICROSECOND, - counter_time); - - if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { - return; - } - - /* make sure that there is enough reusable space in the redo - log files */ - srv_main_thread_op_info = "checking free log space"; - log_free_check(); - - if (srv_shutdown_state > SRV_SHUTDOWN_INITIATED) { - return; - } - srv_main_thread_op_info = "enforcing dict cache limit"; - ulint n_evicted = srv_master_evict_from_table_cache(100); - if (n_evicted != 0) { + if (ulint n_evicted = dict_sys.evict_table_LRU(false)) { MONITOR_INC_VALUE( MONITOR_SRV_DICT_LRU_EVICT_COUNT_IDLE, n_evicted); } MONITOR_INC_TIME_IN_MICRO_SECS( MONITOR_SRV_DICT_LRU_MICROSECOND, counter_time); - - /* Flush logs if needed */ - srv_sync_log_buffer_in_background(); - MONITOR_INC_TIME_IN_MICRO_SECS( - MONITOR_SRV_LOG_FLUSH_MICROSECOND, counter_time); } /** @@ -1649,7 +1500,6 @@ and optionally change buffer merge (on innodb_fast_shutdown=0). */ void srv_shutdown(bool ibuf_merge) { ulint n_read = 0; - ulint n_tables_to_drop; time_t now = time(NULL); do { @@ -1657,11 +1507,6 @@ void srv_shutdown(bool ibuf_merge) ut_ad(srv_shutdown_state == SRV_SHUTDOWN_CLEANUP); ++srv_main_shutdown_loops; - /* FIXME: Remove the background DROP TABLE queue; it is not - crash-safe and breaks ACID. */ - srv_main_thread_op_info = "doing background drop tables"; - n_tables_to_drop = row_drop_tables_for_mysql_in_background(); - if (ibuf_merge) { srv_main_thread_op_info = "doing insert buffer merge"; /* Disallow the use of change buffer to @@ -1670,29 +1515,32 @@ void srv_shutdown(bool ibuf_merge) ibuf_max_size_update(0); log_free_check(); n_read = ibuf_contract(); + srv_shutdown_print(now, n_read); } - - if (n_tables_to_drop || ibuf_merge) { - srv_shutdown_print(now, n_tables_to_drop, n_read); - } - } while (n_read || n_tables_to_drop); + } while (n_read); } /** The periodic master task controlling the server. */ void srv_master_callback(void*) { - static ulint old_activity_count; + static ulint old_activity_count; - ut_a(srv_shutdown_state <= SRV_SHUTDOWN_INITIATED); + ut_a(srv_shutdown_state <= SRV_SHUTDOWN_INITIATED); - srv_main_thread_op_info = ""; - MONITOR_INC(MONITOR_MASTER_THREAD_SLEEP); - if (srv_check_activity(&old_activity_count)) { - srv_master_do_active_tasks(); - } else { - srv_master_do_idle_tasks(); - } - srv_main_thread_op_info = "sleeping"; + MONITOR_INC(MONITOR_MASTER_THREAD_SLEEP); + if (!purge_state.m_running) + srv_wake_purge_thread_if_not_active(); + ulonglong counter_time= microsecond_interval_timer(); + srv_sync_log_buffer_in_background(); + MONITOR_INC_TIME_IN_MICRO_SECS(MONITOR_SRV_LOG_FLUSH_MICROSECOND, + counter_time); + + if (srv_check_activity(&old_activity_count)) + srv_master_do_active_tasks(counter_time); + else + srv_master_do_idle_tasks(counter_time); + + srv_main_thread_op_info= "sleeping"; } /** @return whether purge should exit due to shutdown */ @@ -1707,7 +1555,8 @@ static bool srv_purge_should_exit() return true; /* Slow shutdown was requested. */ - if (const size_t history_size= trx_sys.rseg_history_len) + const size_t history_size= trx_sys.history_size(); + if (history_size) { static time_t progress_time; time_t now= time(NULL); @@ -1718,7 +1567,7 @@ static bool srv_purge_should_exit() service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, "InnoDB: to purge %zu transactions", history_size); - ib::info() << "to purge " << history_size << " transactions"; + sql_print_information("InnoDB: to purge %zu transactions", history_size); #endif } return false; @@ -1736,18 +1585,18 @@ static bool srv_task_execute() ut_ad(!srv_read_only_mode); ut_ad(srv_force_recovery < SRV_FORCE_NO_BACKGROUND); - mutex_enter(&srv_sys.tasks_mutex); + mysql_mutex_lock(&srv_sys.tasks_mutex); if (que_thr_t* thr = UT_LIST_GET_FIRST(srv_sys.tasks)) { ut_a(que_node_get_type(thr->child) == QUE_NODE_PURGE); UT_LIST_REMOVE(srv_sys.tasks, thr); - mutex_exit(&srv_sys.tasks_mutex); + mysql_mutex_unlock(&srv_sys.tasks_mutex); que_run_threads(thr); return true; } ut_ad(UT_LIST_GET_LEN(srv_sys.tasks) == 0); - mutex_exit(&srv_sys.tasks_mutex); + mysql_mutex_unlock(&srv_sys.tasks_mutex); return false; } @@ -1764,89 +1613,175 @@ void srv_update_purge_thread_count(uint n) Atomic_counter<int> srv_purge_thread_count_changed; -/** Do the actual purge operation. -@param[in,out] n_total_purged total number of purged pages -@return length of history list before the last purge batch. */ -static size_t srv_do_purge(ulint* n_total_purged) +inline void purge_coordinator_state::do_purge() { - ulint n_pages_purged; + ut_ad(!srv_read_only_mode); + lazy_init(); + ut_ad(n_threads); + bool wakeup= false; - static ulint count = 0; - static ulint n_use_threads = 0; - static size_t rseg_history_len = 0; - ulint old_activity_count = srv_get_activity_count(); - static ulint n_threads = srv_n_purge_threads; + purge_coordinator_timer->disarm(); - ut_a(n_threads > 0); - ut_ad(!srv_read_only_mode); + while (purge_sys.enabled() && !purge_sys.paused()) + { +loop: + wakeup= false; + const auto now= my_interval_timer(); + const auto sigcount= m_running; + + if (now - start_time >= 1000000) + { + refresh(false); + start_time= now; + } - /* Purge until there are no more records to purge and there is - no change in configuration or server state. If the user has - configured more than one purge thread then we treat that as a - pool of threads and only use the extra threads if purge can't - keep up with updates. */ + const auto old_activity_count= srv_sys.activity_count; + const auto history_size= trx_sys.history_size(); - if (n_use_threads == 0) { - n_use_threads = n_threads; - } + if (UNIV_UNLIKELY(srv_purge_thread_count_changed)) + { + /* Read the fresh value of srv_n_purge_threads, reset + the changed flag. Both are protected by purge_thread_count_mtx. - do { - if (UNIV_UNLIKELY(srv_purge_thread_count_changed)) { - /* Read the fresh value of srv_n_purge_threads, reset - the changed flag. Both variables are protected by - purge_thread_count_mtx. - - This code does not run concurrently, it is executed - by a single purge_coordinator thread, and no races - involving srv_purge_thread_count_changed are possible. - */ - - std::lock_guard<std::mutex> lk(purge_thread_count_mtx); - n_threads = n_use_threads = srv_n_purge_threads; - srv_purge_thread_count_changed = 0; - } else if (trx_sys.rseg_history_len > rseg_history_len - || (srv_max_purge_lag > 0 - && rseg_history_len > srv_max_purge_lag)) { - - /* History length is now longer than what it was - when we took the last snapshot. Use more threads. */ - - if (n_use_threads < n_threads) { - ++n_use_threads; - } + This code does not run concurrently, it is executed + by a single purge_coordinator thread, and no races + involving srv_purge_thread_count_changed are possible. */ + { + std::lock_guard<std::mutex> lk(purge_thread_count_mtx); + n_threads= n_use_threads= srv_n_purge_threads; + srv_purge_thread_count_changed= 0; + } + refresh(true); + start_time= now; + } + else if (history_size > m_history_length) + { + /* dynamically adjust the purge thread based on redo log fill factor */ + if (n_use_threads < n_threads && lsn_age_factor < lsn_lwm) + { +more_threads: + ++n_use_threads; + lsn_hwm= lsn_lwm; + lsn_lwm-= series[n_use_threads]; + } + else if (n_use_threads > 1 && lsn_age_factor >= lsn_hwm) + { +fewer_threads: + --n_use_threads; + lsn_lwm= lsn_hwm; + lsn_hwm+= series[n_use_threads]; + } + else if (n_use_threads == 1 && lsn_age_factor >= 100 - safety_net) + { + wakeup= true; + break; + } + } + else if (n_threads > n_use_threads && + srv_max_purge_lag && m_history_length > srv_max_purge_lag) + goto more_threads; + else if (n_use_threads > 1 && old_activity_count == srv_sys.activity_count) + goto fewer_threads; + + ut_ad(n_use_threads); + ut_ad(n_use_threads <= n_threads); + + m_history_length= history_size; + + if (history_size && + trx_purge(n_use_threads, + !(++count % srv_purge_rseg_truncate_frequency) || + purge_sys.truncate.current || + (srv_shutdown_state != SRV_SHUTDOWN_NONE && + srv_fast_shutdown == 0))) + continue; + + if (m_running == sigcount) + { + /* Purge was not woken up by srv_wake_purge_thread_if_not_active() */ + + /* The magic number 5000 is an approximation for the case where we have + cached undo log records which prevent truncate of rollback segments. */ + wakeup= history_size && + (history_size >= 5000 || + history_size != trx_sys.history_size_approx()); + break; + } + else if (!trx_sys.history_exists()) + break; - } else if (srv_check_activity(&old_activity_count) - && n_use_threads > 1) { + if (!srv_purge_should_exit()) + goto loop; + } - /* History length same or smaller since last snapshot, - use fewer threads. */ + if (wakeup) + purge_coordinator_timer->set_time(10, 0); - --n_use_threads; - } + m_running= 0; +} - /* Ensure that the purge threads are less than what - was configured. */ +inline void purge_coordinator_state::compute_series() +{ + ulint points= n_threads; + memset(series, 0, sizeof series); + constexpr ulint spread= 100 - adaptive_purge_threshold - safety_net; - ut_a(n_use_threads > 0); - ut_a(n_use_threads <= n_threads); + /* We distribute spread across n_threads, + e.g.: spread of 60 is distributed across n_threads=4 as: 6+12+18+24 */ - /* Take a snapshot of the history list before purge. */ - if (!(rseg_history_len = trx_sys.rseg_history_len)) { - break; - } + const ulint additional_points= (points * (points + 1)) / 2; + if (spread % additional_points == 0) + { + /* Arithmetic progression is possible. */ + const ulint delta= spread / additional_points; + ulint growth= delta; + do + { + series[points--]= growth; + growth += delta; + } + while (points); + return; + } - n_pages_purged = trx_purge( - n_use_threads, - !(++count % srv_purge_rseg_truncate_frequency) - || purge_sys.truncate.current - || (srv_shutdown_state != SRV_SHUTDOWN_NONE - && srv_fast_shutdown == 0)); + /* Use average distribution to spread across the points */ + const ulint delta= spread / points; + ulint total= 0; + do + { + series[points--]= delta; + total+= delta; + } + while (points); - *n_total_purged += n_pages_purged; - } while (n_pages_purged > 0 && !purge_sys.paused() - && !srv_purge_should_exit()); + for (points= 1; points <= n_threads && total++ < spread; ) + series[points++]++; +} + +inline void purge_coordinator_state::lazy_init() +{ + if (n_threads) + return; + n_threads= n_use_threads= srv_n_purge_threads; + refresh(true); + start_time= my_interval_timer(); +} + +void purge_coordinator_state::refresh(bool full) +{ + if (full) + { + compute_series(); + lsn_lwm= adaptive_purge_threshold; + lsn_hwm= adaptive_purge_threshold + series[n_threads]; + } - return(rseg_history_len); + mysql_mutex_lock(&log_sys.mutex); + const lsn_t last= log_sys.last_checkpoint_lsn, + max_age= log_sys.max_checkpoint_age; + mysql_mutex_unlock(&log_sys.mutex); + + lsn_age_factor= ulint(((log_sys.get_lsn() - last) * 100) / max_age); } @@ -1892,27 +1827,6 @@ static void release_thd(THD *thd, void *ctx) set_current_thd(0); } - -/* - Called by timer when purge coordinator decides - to delay processing of purge records. -*/ -static void purge_coordinator_timer_callback(void *) -{ - if (!purge_sys.enabled() || purge_sys.paused() || - purge_state.m_running || !trx_sys.rseg_history_len) - return; - - if (purge_state.m_history_length < 5000 && - purge_state.m_history_length == trx_sys.rseg_history_len) - /* No new records were added since wait started. - Simply wait for new records. The magic number 5000 is an - approximation for the case where we have cached UNDO - log records which prevent truncate of the UNDO segments.*/ - return; - srv_wake_purge_thread_if_not_active(); -} - static void purge_worker_callback(void*) { ut_ad(!current_thd); @@ -1925,62 +1839,24 @@ static void purge_worker_callback(void*) release_thd(thd,ctx); } -static void purge_coordinator_callback_low() -{ - ulint n_total_purged= ULINT_UNDEFINED; - purge_state.m_history_length= 0; - - if (!purge_sys.enabled() || purge_sys.paused()) - return; - do - { - n_total_purged = 0; - int sigcount= purge_state.m_running; - - purge_state.m_history_length= srv_do_purge(&n_total_purged); - - /* Check if purge was woken by srv_wake_purge_thread_if_not_active() */ - - bool woken_during_purge= purge_state.m_running > sigcount; - - /* If last purge batch processed less than 1 page and there is - still work to do, delay the next batch by 10ms. Unless - someone added work and woke us up. */ - if (n_total_purged == 0) - { - if (trx_sys.rseg_history_len == 0) - return; - if (!woken_during_purge) - { - /* Delay next purge round*/ - purge_coordinator_timer->set_time(10, 0); - return; - } - } - } - while ((purge_sys.enabled() && !purge_sys.paused()) || - !srv_purge_should_exit()); -} - static void purge_coordinator_callback(void*) { void *ctx; THD *thd= acquire_thd(&ctx); - purge_coordinator_callback_low(); - release_thd(thd,ctx); - purge_state.m_running= 0; + purge_state.do_purge(); + release_thd(thd, ctx); } void srv_init_purge_tasks() { purge_create_background_thds(srv_n_purge_threads); purge_coordinator_timer= srv_thread_pool->create_timer - (purge_coordinator_timer_callback, nullptr); + (purge_coordinator_callback, nullptr); } static void srv_shutdown_purge_tasks() { - purge_coordinator_task.wait(); + purge_coordinator_task.disable(); delete purge_coordinator_timer; purge_coordinator_timer= nullptr; purge_worker_task.wait(); @@ -2002,11 +1878,11 @@ srv_que_task_enqueue_low( que_thr_t* thr) /*!< in: query thread */ { ut_ad(!srv_read_only_mode); - mutex_enter(&srv_sys.tasks_mutex); + mysql_mutex_lock(&srv_sys.tasks_mutex); UT_LIST_ADD_LAST(srv_sys.tasks, thr); - mutex_exit(&srv_sys.tasks_mutex); + mysql_mutex_unlock(&srv_sys.tasks_mutex); } #ifdef UNIV_DEBUG @@ -2017,11 +1893,11 @@ ulint srv_get_task_queue_length() ut_ad(!srv_read_only_mode); - mutex_enter(&srv_sys.tasks_mutex); + mysql_mutex_lock(&srv_sys.tasks_mutex); n_tasks = UT_LIST_GET_LEN(srv_sys.tasks); - mutex_exit(&srv_sys.tasks_mutex); + mysql_mutex_unlock(&srv_sys.tasks_mutex); return(n_tasks); } |