Skip to content

Commit 657fcdf

Browse files
committed
MDEV-24280 InnoDB triggers too many independent periodic tasks
A side effect of MDEV-16264 is that a large number of threads will be created at server startup, to be destroyed after a minute or two. One source of such thread creation is srv_start_periodic_timer(). InnoDB is creating 3 periodic tasks: srv_master_callback (1Hz) srv_error_monitor_task (1Hz), and srv_monitor_task (0.2Hz). It appears that we can merge srv_error_monitor_task and srv_monitor_task and have them invoked 4 times per minute (every 15 seconds). This will affect our ability to enforce innodb_fatal_semaphore_wait_threshold and some computations around BUF_LRU_STAT_N_INTERVAL. We could remove srv_master_callback along with the DROP TABLE queue at some point of time in the future. We must keep it independent of the innodb_fatal_semaphore_wait_threshold detection, because the background DROP TABLE queue could get stuck due to dict_sys being locked by another thread. For now, srv_master_callback must be invoked once per second, so that innodb_flush_log_at_timeout=1 can work. BUF_LRU_STAT_N_INTERVAL: Reduce the precision and extend the time from 50*1 second to 4*15 seconds. srv_error_monitor_timer: Remove. MAX_MUTEX_NOWAIT: Increase from 20*1 second to 2*15 seconds. srv_refresh_innodb_monitor_stats(): Avoid a repeated call to time(NULL). Change the interval to less than 60 seconds. srv_monitor(): Renamed from srv_monitor_task. srv_monitor_task(): Renamed from srv_error_monitor_task(). Invoked only once in 15 seconds. Invoke also srv_monitor(). Increase the fatal_cnt threshold from 10*1 second to 1*15 seconds. sync_array_print_long_waits_low(): Invoke time(NULL) only once. Remove a bogus message about printouts for 30 seconds. Those printouts were effectively already disabled in MDEV-16264 (commit 5e62b6a).
1 parent 7b1252c commit 657fcdf

File tree

6 files changed

+33
-67
lines changed

6 files changed

+33
-67
lines changed

storage/innobase/buf/buf0lru.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,12 @@ uncompressed and compressed data), which must be clean. */
7676
/* @{ */
7777

7878
/** Number of intervals for which we keep the history of these stats.
79-
Each interval is 1 second, defined by the rate at which
80-
srv_error_monitor_thread() calls buf_LRU_stat_update(). */
81-
static const ulint BUF_LRU_STAT_N_INTERVAL = 50;
79+
Updated at SRV_MONITOR_INTERVAL (the buf_LRU_stat_update() call rate). */
80+
static constexpr ulint BUF_LRU_STAT_N_INTERVAL= 4;
8281

8382
/** Co-efficient with which we multiply I/O operations to equate them
8483
with page_zip_decompress() operations. */
85-
static const ulint BUF_LRU_IO_TO_UNZIP_FACTOR = 50;
84+
static constexpr ulint BUF_LRU_IO_TO_UNZIP_FACTOR= 50;
8685

8786
/** Sampled values buf_LRU_stat_cur.
8887
Not protected by any mutex. Updated by buf_LRU_stat_update(). */

storage/innobase/include/srv0srv.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -702,13 +702,6 @@ Complete the shutdown tasks such as background DROP TABLE,
702702
and optionally change buffer merge (on innodb_fast_shutdown=0). */
703703
void srv_shutdown(bool ibuf_merge);
704704

705-
706-
/*************************************************************************
707-
A task which prints warnings about semaphore waits which have lasted
708-
too long. These can be used to track bugs which cause hangs.
709-
*/
710-
void srv_error_monitor_task(void*);
711-
712705
} /* extern "C" */
713706

714707
#ifdef UNIV_DEBUG
@@ -900,12 +893,14 @@ struct srv_slot_t{
900893

901894
extern tpool::thread_pool *srv_thread_pool;
902895
extern std::unique_ptr<tpool::timer> srv_master_timer;
903-
extern std::unique_ptr<tpool::timer> srv_error_monitor_timer;
904896
extern std::unique_ptr<tpool::timer> srv_monitor_timer;
905897

898+
/** The interval at which srv_monitor_task is invoked, in milliseconds */
899+
constexpr unsigned SRV_MONITOR_INTERVAL= 15000; /* 4 times per minute */
900+
906901
static inline void srv_monitor_timer_schedule_now()
907902
{
908-
srv_monitor_timer->set_time(0, 5000);
903+
srv_monitor_timer->set_time(0, SRV_MONITOR_INTERVAL);
909904
}
910905
static inline void srv_start_periodic_timer(std::unique_ptr<tpool::timer>& t,
911906
void (*func)(void*), int period)

storage/innobase/log/log0log.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,6 @@ ATTRIBUTE_COLD void logs_empty_and_mark_files_at_shutdown()
10111011
!srv_read_only_mode && srv_fast_shutdown < 2) {
10121012
buf_dump_start();
10131013
}
1014-
srv_error_monitor_timer.reset();
10151014
srv_monitor_timer.reset();
10161015
lock_sys.timeout_timer.reset();
10171016
if (do_srv_shutdown) {

storage/innobase/srv/srv0srv.cc

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ tpool::thread_pool* srv_thread_pool;
186186

187187
/** Maximum number of times allowed to conditionally acquire
188188
mutex before switching to blocking wait on the mutex */
189-
#define MAX_MUTEX_NOWAIT 20
189+
#define MAX_MUTEX_NOWAIT 2
190190

191191
/** Check whether the number of failed nonblocking mutex
192192
acquisition attempts exceeds maximum allowed value. If so,
@@ -555,8 +555,7 @@ struct purge_coordinator_state
555555

556556
static purge_coordinator_state purge_state;
557557

558-
/** threadpool timer for srv_error_monitor_task(). */
559-
std::unique_ptr<tpool::timer> srv_error_monitor_timer;
558+
/** threadpool timer for srv_monitor_task() */
560559
std::unique_ptr<tpool::timer> srv_monitor_timer;
561560

562561

@@ -769,16 +768,11 @@ srv_boot(void)
769768

770769
/******************************************************************//**
771770
Refreshes the values used to calculate per-second averages. */
772-
static
773-
void
774-
srv_refresh_innodb_monitor_stats(void)
775-
/*==================================*/
771+
static void srv_refresh_innodb_monitor_stats(time_t current_time)
776772
{
777773
mutex_enter(&srv_innodb_monitor_mutex);
778774

779-
time_t current_time = time(NULL);
780-
781-
if (difftime(current_time, srv_last_monitor_time) <= 60) {
775+
if (difftime(current_time, srv_last_monitor_time) < 60) {
782776
/* We referesh InnoDB Monitor values so that averages are
783777
printed from at most 60 last seconds */
784778
mutex_exit(&srv_innodb_monitor_mutex);
@@ -1309,26 +1303,18 @@ struct srv_monitor_state_t
13091303
static srv_monitor_state_t monitor_state;
13101304

13111305
/** A task which prints the info output by various InnoDB monitors.*/
1312-
void srv_monitor_task(void*)
1306+
static void srv_monitor()
13131307
{
1314-
double time_elapsed;
1315-
time_t current_time;
1316-
1317-
ut_ad(!srv_read_only_mode);
1318-
1319-
current_time = time(NULL);
1320-
1321-
time_elapsed = difftime(current_time, monitor_state.last_monitor_time);
1308+
time_t current_time = time(NULL);
13221309

1323-
if (time_elapsed > 15) {
1310+
if (difftime(current_time, monitor_state.last_monitor_time) >= 15) {
13241311
monitor_state.last_monitor_time = current_time;
13251312

13261313
if (srv_print_innodb_monitor) {
13271314
/* Reset mutex_skipped counter everytime
13281315
srv_print_innodb_monitor changes. This is to
13291316
ensure we will not be blocked by lock_sys.mutex
1330-
for short duration information printing,
1331-
such as requested by sync_array_print_long_waits() */
1317+
for short duration information printing */
13321318
if (!monitor_state.last_srv_print_monitor) {
13331319
monitor_state.mutex_skipped = 0;
13341320
monitor_state.last_srv_print_monitor = true;
@@ -1366,14 +1352,14 @@ void srv_monitor_task(void*)
13661352
}
13671353
}
13681354

1369-
srv_refresh_innodb_monitor_stats();
1355+
srv_refresh_innodb_monitor_stats(current_time);
13701356
}
13711357

13721358
/*********************************************************************//**
13731359
A task which prints warnings about semaphore waits which have lasted
13741360
too long. These can be used to track bugs which cause hangs.
13751361
*/
1376-
void srv_error_monitor_task(void*)
1362+
void srv_monitor_task(void*)
13771363
{
13781364
/* number of successive fatal timeouts observed */
13791365
static ulint fatal_cnt;
@@ -1408,20 +1394,17 @@ void srv_error_monitor_task(void*)
14081394
if (sync_array_print_long_waits(&waiter, &sema)
14091395
&& sema == old_sema && os_thread_eq(waiter, old_waiter)) {
14101396
#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES)
1411-
if (os_event_is_set(srv_allow_writes_event)) {
1412-
#endif /* WITH_WSREP */
1413-
fatal_cnt++;
1414-
#if defined(WITH_WSREP) && defined(WITH_INNODB_DISALLOW_WRITES)
1415-
} else {
1416-
fprintf(stderr,
1417-
"WSREP: avoiding InnoDB self crash due to long "
1418-
"semaphore wait of > %lu seconds\n"
1419-
"Server is processing SST donor operation, "
1420-
"fatal_cnt now: " ULINTPF,
1421-
srv_fatal_semaphore_wait_threshold, fatal_cnt);
1422-
}
1397+
if (!os_event_is_set(srv_allow_writes_event)) {
1398+
fprintf(stderr,
1399+
"WSREP: avoiding InnoDB self crash due to "
1400+
"long semaphore wait of > %lu seconds\n"
1401+
"Server is processing SST donor operation, "
1402+
"fatal_cnt now: " ULINTPF,
1403+
srv_fatal_semaphore_wait_threshold, fatal_cnt);
1404+
return;
1405+
}
14231406
#endif /* WITH_WSREP */
1424-
if (fatal_cnt > 10) {
1407+
if (fatal_cnt++) {
14251408
ib::fatal() << "Semaphore wait has lasted > "
14261409
<< srv_fatal_semaphore_wait_threshold
14271410
<< " seconds. We intentionally crash the"
@@ -1432,6 +1415,8 @@ void srv_error_monitor_task(void*)
14321415
old_waiter = waiter;
14331416
old_sema = sema;
14341417
}
1418+
1419+
srv_monitor();
14351420
}
14361421

14371422
/******************************************************************//**

storage/innobase/srv/srv0start.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,8 +1826,8 @@ dberr_t srv_start(bool create_new_db)
18261826

18271827
DBUG_EXECUTE_IF("innodb_skip_monitors", goto skip_monitors;);
18281828
/* Create the task which warns of long semaphore waits */
1829-
srv_start_periodic_timer(srv_error_monitor_timer, srv_error_monitor_task, 1000);
1830-
srv_start_periodic_timer(srv_monitor_timer, srv_monitor_task, 5000);
1829+
srv_start_periodic_timer(srv_monitor_timer, srv_monitor_task,
1830+
SRV_MONITOR_INTERVAL);
18311831

18321832
#ifndef DBUG_OFF
18331833
skip_monitors:

storage/innobase/sync/sync0arr.cc

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,7 @@ sync_array_print_long_waits_low(
893893
#else
894894
# define SYNC_ARRAY_TIMEOUT 240
895895
#endif
896+
const time_t now = time(NULL);
896897

897898
for (ulint i = 0; i < arr->n_cells; i++) {
898899

@@ -908,7 +909,7 @@ sync_array_print_long_waits_low(
908909
continue;
909910
}
910911

911-
double diff = difftime(time(NULL), cell->reservation_time);
912+
double diff = difftime(now, cell->reservation_time);
912913

913914
if (diff > SYNC_ARRAY_TIMEOUT) {
914915
ib::warn() << "A long semaphore wait:";
@@ -982,12 +983,6 @@ sync_array_print_long_waits(
982983
}
983984

984985
if (noticed) {
985-
fprintf(stderr,
986-
"InnoDB: ###### Starts InnoDB Monitor"
987-
" for 30 secs to print diagnostic info:\n");
988-
989-
my_bool old_val = srv_print_innodb_monitor;
990-
991986
/* If some crucial semaphore is reserved, then also the InnoDB
992987
Monitor can hang, and we do not get diagnostics. Since in
993988
many cases an InnoDB hang is caused by a pwrite() or a pread()
@@ -1000,14 +995,7 @@ sync_array_print_long_waits(
1000995
MONITOR_VALUE(MONITOR_OS_PENDING_READS),
1001996
MONITOR_VALUE(MONITOR_OS_PENDING_WRITES));
1002997

1003-
srv_print_innodb_monitor = TRUE;
1004-
1005998
lock_wait_timeout_task(nullptr);
1006-
1007-
srv_print_innodb_monitor = static_cast<my_bool>(old_val);
1008-
fprintf(stderr,
1009-
"InnoDB: ###### Diagnostic info printed"
1010-
" to the standard error stream\n");
1011999
}
10121000

10131001
return(fatal);

0 commit comments

Comments
 (0)