diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2017-04-26 10:30:13 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2017-04-26 23:03:31 +0300 |
commit | 13dcdb0903f30130e69e2d6c7cf7770a3d3b9427 (patch) | |
tree | 37532049c3de95fa0a9e397829b08015800787d3 /storage/innobase | |
parent | 731435af9a3e0fae7555439f65f58c79e92da857 (diff) | |
download | mariadb-git-13dcdb0903f30130e69e2d6c7cf7770a3d3b9427.tar.gz |
MDEV-11802 InnoDB purge does not always run when there is work to do
srv_sys_t::n_threads_active[]: Protect writes by both the mutex and
by atomic memory access.
srv_active_wake_master_thread_low(): Reliably wake up the master
thread if there is work to do. The trick is to atomically read
srv_sys->n_threads_active[].
srv_wake_purge_thread_if_not_active(): Atomically read
srv_sys->n_threads_active[] (and trx_sys->rseg_history_len),
so that the purge should always be triggered when there is work to do.
trx_commit_in_memory(): Invoke srv_wake_purge_thread_if_not_active()
whenever a transaction is committed. Purge could have been prevented by
the read view of the currently committing transaction, even if it is
a read-only transaction.
trx_purge_add_update_undo_to_history(): Do not wake up the purge.
This is only called by trx_undo_update_cleanup(), as part of
trx_write_serialisation_history(), which in turn is only called by
trx_commit_low() which will always call trx_commit_in_memory().
Thus, the added call in trx_commit_in_memory() will cover also
this use case where a committing read-write transaction added
some update_undo log to the purge queue.
trx_rseg_mem_restore(): Atomically modify trx_sys->rseg_history_len.
Diffstat (limited to 'storage/innobase')
-rw-r--r-- | storage/innobase/include/srv0srv.h | 30 | ||||
-rw-r--r-- | storage/innobase/srv/srv0srv.cc | 57 | ||||
-rw-r--r-- | storage/innobase/trx/trx0purge.cc | 1 | ||||
-rw-r--r-- | storage/innobase/trx/trx0rseg.cc | 2 | ||||
-rw-r--r-- | storage/innobase/trx/trx0trx.cc | 1 |
5 files changed, 30 insertions, 61 deletions
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 6803047ed91..230d7b7effe 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -749,36 +749,24 @@ srv_set_io_thread_op_info( Resets the info describing an i/o thread current state. */ void srv_reset_io_thread_op_info(); -/*=========================*/ -/*******************************************************************//** -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). */ + +/** Wake up the purge threads if there is work to do. */ void -srv_wake_purge_thread_if_not_active(void); -/*=====================================*/ -/*******************************************************************//** -Tells the Innobase server that there has been activity in the database -and wakes up the master thread if it is suspended (not sleeping). Used -in the MySQL interface. Note that there is a small chance that the master -thread stays suspended (we do not protect our operation with the kernel -mutex, for performace reasons). */ +srv_wake_purge_thread_if_not_active(); +/** Wake up the InnoDB master thread if it was suspended (not sleeping). */ void -srv_active_wake_master_thread_low(void); -/*===================================*/ +srv_active_wake_master_thread_low(); + #define srv_active_wake_master_thread() \ do { \ if (!srv_read_only_mode) { \ srv_active_wake_master_thread_low(); \ } \ } while (0) -/*******************************************************************//** -Wakes up the master thread if it is suspended or being suspended. */ +/** Wake up the master thread if it is suspended or being suspended. */ void -srv_wake_master_thread(void); -/*========================*/ +srv_wake_master_thread(); + /******************************************************************//** Outputs to a file the output of the InnoDB Monitor. @return FALSE if not all information printed diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index aa795e972a2..8c62cc976b1 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -648,14 +648,16 @@ struct srv_sys_t{ ulint n_threads_active[SRV_MASTER + 1]; /*!< number of threads active - in a thread class */ + in a thread class; protected + by both my_atomic_addlint() + and mutex */ srv_stats_t::ulint_ctr_1_t activity_count; /*!< For tracking server activity */ }; -static srv_sys_t* srv_sys = NULL; +static srv_sys_t* srv_sys; /** Event to signal srv_monitor_thread. Not protected by a mutex. Set after setting srv_print_innodb_monitor. */ @@ -853,7 +855,7 @@ srv_reserve_slot( ut_ad(srv_slot_get_type(slot) == type); - ++srv_sys->n_threads_active[type]; + my_atomic_addlint(&srv_sys->n_threads_active[type], 1); srv_sys_mutex_exit(); @@ -894,16 +896,15 @@ srv_suspend_thread_low( case SRV_WORKER: ut_a(srv_n_purge_threads > 1); - ut_a(srv_sys->n_threads_active[type] > 0); break; } ut_a(!slot->suspended); slot->suspended = TRUE; - ut_a(srv_sys->n_threads_active[type] > 0); - - srv_sys->n_threads_active[type]--; + if (my_atomic_addlint(&srv_sys->n_threads_active[type], -1) < 0) { + ut_error; + } return(os_event_reset(slot->event)); } @@ -958,7 +959,7 @@ srv_resume_thread(srv_slot_t* slot, int64_t sig_count = 0, bool wait = true, ut_ad(slot->suspended); slot->suspended = FALSE; - ++srv_sys->n_threads_active[slot->type]; + my_atomic_addlint(&srv_sys->n_threads_active[slot->type], 1); srv_sys_mutex_exit(); return(timeout); } @@ -2066,22 +2067,16 @@ srv_get_active_thread_type(void) return(ret); } -/*******************************************************************//** -Tells the InnoDB server that there has been activity in the database -and wakes up the master thread if it is suspended (not sleeping). Used -in the MySQL interface. Note that there is a small chance that the master -thread stays suspended (we do not protect our operation with the -srv_sys_t->mutex, for performance reasons). */ +/** Wake up the InnoDB master thread if it was suspended (not sleeping). */ void srv_active_wake_master_thread_low() -/*===============================*/ { ut_ad(!srv_read_only_mode); ut_ad(!srv_sys_mutex_own()); srv_inc_activity_count(); - if (srv_sys->n_threads_active[SRV_MASTER] == 0) { + if (my_atomic_loadlint(&srv_sys->n_threads_active[SRV_MASTER]) == 0) { srv_slot_t* slot; srv_sys_mutex_enter(); @@ -2099,35 +2094,25 @@ srv_active_wake_master_thread_low() } } -/*******************************************************************//** -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 check with the srv_sys_t:mutex and the -purge_sys->latch, for performance reasons). */ +/** Wake up the purge threads if there is work to do. */ void -srv_wake_purge_thread_if_not_active(void) -/*=====================================*/ +srv_wake_purge_thread_if_not_active() { ut_ad(!srv_sys_mutex_own()); if (purge_sys->state == PURGE_STATE_RUN - && srv_sys->n_threads_active[SRV_PURGE] == 0) { + && !my_atomic_loadlint(&srv_sys->n_threads_active[SRV_PURGE]) + && my_atomic_loadlint(&trx_sys->rseg_history_len)) { srv_release_threads(SRV_PURGE, 1); } } -/*******************************************************************//** -Wakes up the master thread if it is suspended or being suspended. */ +/** Wake up the master thread if it is suspended or being suspended. */ void -srv_wake_master_thread(void) -/*========================*/ +srv_wake_master_thread() { - ut_ad(!srv_sys_mutex_own()); - srv_inc_activity_count(); - srv_release_threads(SRV_MASTER, 1); } @@ -2713,12 +2698,8 @@ DECLARE_THREAD(srv_worker_thread)( slot = srv_reserve_slot(SRV_WORKER); ut_a(srv_n_purge_threads > 1); - - srv_sys_mutex_enter(); - - ut_a(srv_sys->n_threads_active[SRV_WORKER] < srv_n_purge_threads); - - srv_sys_mutex_exit(); + ut_a(my_atomic_loadlint(&srv_sys->n_threads_active[SRV_WORKER]) + < static_cast<lint>(srv_n_purge_threads)); /* We need to ensure that the worker threads exit after the purge coordinator thread. Otherwise the purge coordinator can diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 42ae4890cab..b21ec75c3a6 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -291,7 +291,6 @@ trx_purge_add_update_undo_to_history( undo_header + TRX_UNDO_HISTORY_NODE, mtr); my_atomic_addlint(&trx_sys->rseg_history_len, 1); - srv_wake_purge_thread_if_not_active(); /* Write the trx number to the undo log header */ mlog_write_ull(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr); diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index 3393a0464a8..663566cf26f 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -204,7 +204,7 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, mtr_t* mtr) len = flst_get_len(rseg_header + TRX_RSEG_HISTORY); if (len > 0) { - trx_sys->rseg_history_len += len; + my_atomic_addlint(&trx_sys->rseg_history_len, len); node_addr = trx_purge_get_log_from_hist( flst_get_last(rseg_header + TRX_RSEG_HISTORY, mtr)); diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 36324c43970..d6755fca7c0 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1908,6 +1908,7 @@ trx_commit_in_memory( trx_mutex_exit(trx); ut_a(trx->error_state == DB_SUCCESS); + srv_wake_purge_thread_if_not_active(); } /****************************************************************//** |