Skip to content

Commit 13dcdb0

Browse files
committed
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.
1 parent 731435a commit 13dcdb0

File tree

5 files changed

+30
-61
lines changed

5 files changed

+30
-61
lines changed

storage/innobase/include/srv0srv.h

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -749,36 +749,24 @@ srv_set_io_thread_op_info(
749749
Resets the info describing an i/o thread current state. */
750750
void
751751
srv_reset_io_thread_op_info();
752-
/*=========================*/
753-
/*******************************************************************//**
754-
Tells the purge thread that there has been activity in the database
755-
and wakes up the purge thread if it is suspended (not sleeping). Note
756-
that there is a small chance that the purge thread stays suspended
757-
(we do not protect our operation with the srv_sys_t:mutex, for
758-
performance reasons). */
752+
753+
/** Wake up the purge threads if there is work to do. */
759754
void
760-
srv_wake_purge_thread_if_not_active(void);
761-
/*=====================================*/
762-
/*******************************************************************//**
763-
Tells the Innobase server that there has been activity in the database
764-
and wakes up the master thread if it is suspended (not sleeping). Used
765-
in the MySQL interface. Note that there is a small chance that the master
766-
thread stays suspended (we do not protect our operation with the kernel
767-
mutex, for performace reasons). */
755+
srv_wake_purge_thread_if_not_active();
756+
/** Wake up the InnoDB master thread if it was suspended (not sleeping). */
768757
void
769-
srv_active_wake_master_thread_low(void);
770-
/*===================================*/
758+
srv_active_wake_master_thread_low();
759+
771760
#define srv_active_wake_master_thread() \
772761
do { \
773762
if (!srv_read_only_mode) { \
774763
srv_active_wake_master_thread_low(); \
775764
} \
776765
} while (0)
777-
/*******************************************************************//**
778-
Wakes up the master thread if it is suspended or being suspended. */
766+
/** Wake up the master thread if it is suspended or being suspended. */
779767
void
780-
srv_wake_master_thread(void);
781-
/*========================*/
768+
srv_wake_master_thread();
769+
782770
/******************************************************************//**
783771
Outputs to a file the output of the InnoDB Monitor.
784772
@return FALSE if not all information printed

storage/innobase/srv/srv0srv.cc

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -648,14 +648,16 @@ struct srv_sys_t{
648648

649649
ulint n_threads_active[SRV_MASTER + 1];
650650
/*!< number of threads active
651-
in a thread class */
651+
in a thread class; protected
652+
by both my_atomic_addlint()
653+
and mutex */
652654

653655
srv_stats_t::ulint_ctr_1_t
654656
activity_count; /*!< For tracking server
655657
activity */
656658
};
657659

658-
static srv_sys_t* srv_sys = NULL;
660+
static srv_sys_t* srv_sys;
659661

660662
/** Event to signal srv_monitor_thread. Not protected by a mutex.
661663
Set after setting srv_print_innodb_monitor. */
@@ -853,7 +855,7 @@ srv_reserve_slot(
853855

854856
ut_ad(srv_slot_get_type(slot) == type);
855857

856-
++srv_sys->n_threads_active[type];
858+
my_atomic_addlint(&srv_sys->n_threads_active[type], 1);
857859

858860
srv_sys_mutex_exit();
859861

@@ -894,16 +896,15 @@ srv_suspend_thread_low(
894896

895897
case SRV_WORKER:
896898
ut_a(srv_n_purge_threads > 1);
897-
ut_a(srv_sys->n_threads_active[type] > 0);
898899
break;
899900
}
900901

901902
ut_a(!slot->suspended);
902903
slot->suspended = TRUE;
903904

904-
ut_a(srv_sys->n_threads_active[type] > 0);
905-
906-
srv_sys->n_threads_active[type]--;
905+
if (my_atomic_addlint(&srv_sys->n_threads_active[type], -1) < 0) {
906+
ut_error;
907+
}
907908

908909
return(os_event_reset(slot->event));
909910
}
@@ -958,7 +959,7 @@ srv_resume_thread(srv_slot_t* slot, int64_t sig_count = 0, bool wait = true,
958959
ut_ad(slot->suspended);
959960

960961
slot->suspended = FALSE;
961-
++srv_sys->n_threads_active[slot->type];
962+
my_atomic_addlint(&srv_sys->n_threads_active[slot->type], 1);
962963
srv_sys_mutex_exit();
963964
return(timeout);
964965
}
@@ -2066,22 +2067,16 @@ srv_get_active_thread_type(void)
20662067
return(ret);
20672068
}
20682069

2069-
/*******************************************************************//**
2070-
Tells the InnoDB server that there has been activity in the database
2071-
and wakes up the master thread if it is suspended (not sleeping). Used
2072-
in the MySQL interface. Note that there is a small chance that the master
2073-
thread stays suspended (we do not protect our operation with the
2074-
srv_sys_t->mutex, for performance reasons). */
2070+
/** Wake up the InnoDB master thread if it was suspended (not sleeping). */
20752071
void
20762072
srv_active_wake_master_thread_low()
2077-
/*===============================*/
20782073
{
20792074
ut_ad(!srv_read_only_mode);
20802075
ut_ad(!srv_sys_mutex_own());
20812076

20822077
srv_inc_activity_count();
20832078

2084-
if (srv_sys->n_threads_active[SRV_MASTER] == 0) {
2079+
if (my_atomic_loadlint(&srv_sys->n_threads_active[SRV_MASTER]) == 0) {
20852080
srv_slot_t* slot;
20862081

20872082
srv_sys_mutex_enter();
@@ -2099,35 +2094,25 @@ srv_active_wake_master_thread_low()
20992094
}
21002095
}
21012096

2102-
/*******************************************************************//**
2103-
Tells the purge thread that there has been activity in the database
2104-
and wakes up the purge thread if it is suspended (not sleeping). Note
2105-
that there is a small chance that the purge thread stays suspended
2106-
(we do not protect our check with the srv_sys_t:mutex and the
2107-
purge_sys->latch, for performance reasons). */
2097+
/** Wake up the purge threads if there is work to do. */
21082098
void
2109-
srv_wake_purge_thread_if_not_active(void)
2110-
/*=====================================*/
2099+
srv_wake_purge_thread_if_not_active()
21112100
{
21122101
ut_ad(!srv_sys_mutex_own());
21132102

21142103
if (purge_sys->state == PURGE_STATE_RUN
2115-
&& srv_sys->n_threads_active[SRV_PURGE] == 0) {
2104+
&& !my_atomic_loadlint(&srv_sys->n_threads_active[SRV_PURGE])
2105+
&& my_atomic_loadlint(&trx_sys->rseg_history_len)) {
21162106

21172107
srv_release_threads(SRV_PURGE, 1);
21182108
}
21192109
}
21202110

2121-
/*******************************************************************//**
2122-
Wakes up the master thread if it is suspended or being suspended. */
2111+
/** Wake up the master thread if it is suspended or being suspended. */
21232112
void
2124-
srv_wake_master_thread(void)
2125-
/*========================*/
2113+
srv_wake_master_thread()
21262114
{
2127-
ut_ad(!srv_sys_mutex_own());
2128-
21292115
srv_inc_activity_count();
2130-
21312116
srv_release_threads(SRV_MASTER, 1);
21322117
}
21332118

@@ -2713,12 +2698,8 @@ DECLARE_THREAD(srv_worker_thread)(
27132698
slot = srv_reserve_slot(SRV_WORKER);
27142699

27152700
ut_a(srv_n_purge_threads > 1);
2716-
2717-
srv_sys_mutex_enter();
2718-
2719-
ut_a(srv_sys->n_threads_active[SRV_WORKER] < srv_n_purge_threads);
2720-
2721-
srv_sys_mutex_exit();
2701+
ut_a(my_atomic_loadlint(&srv_sys->n_threads_active[SRV_WORKER])
2702+
< static_cast<lint>(srv_n_purge_threads));
27222703

27232704
/* We need to ensure that the worker threads exit after the
27242705
purge coordinator thread. Otherwise the purge coordinator can

storage/innobase/trx/trx0purge.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,6 @@ trx_purge_add_update_undo_to_history(
291291
undo_header + TRX_UNDO_HISTORY_NODE, mtr);
292292

293293
my_atomic_addlint(&trx_sys->rseg_history_len, 1);
294-
srv_wake_purge_thread_if_not_active();
295294

296295
/* Write the trx number to the undo log header */
297296
mlog_write_ull(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr);

storage/innobase/trx/trx0rseg.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ trx_rseg_mem_restore(trx_rseg_t* rseg, mtr_t* mtr)
204204
len = flst_get_len(rseg_header + TRX_RSEG_HISTORY);
205205

206206
if (len > 0) {
207-
trx_sys->rseg_history_len += len;
207+
my_atomic_addlint(&trx_sys->rseg_history_len, len);
208208

209209
node_addr = trx_purge_get_log_from_hist(
210210
flst_get_last(rseg_header + TRX_RSEG_HISTORY, mtr));

storage/innobase/trx/trx0trx.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1908,6 +1908,7 @@ trx_commit_in_memory(
19081908
trx_mutex_exit(trx);
19091909

19101910
ut_a(trx->error_state == DB_SUCCESS);
1911+
srv_wake_purge_thread_if_not_active();
19111912
}
19121913

19131914
/****************************************************************//**

0 commit comments

Comments
 (0)