Hi, On Tue, Aug 06, 2024 at 12:36:44PM -0500, Sami Imseih wrote:
> > > v5 takes care of the latest comments by Bertrand. > Thanks! Please find attached a rebase version (due to 39a138fbef) and in passing I changed one comment: "add t in microseconds to a instr_time" -> "add t (in microseconds) to x" Does that make sense to you? That said, it looks good to me. Regards, -- Bertrand Drouvot PostgreSQL Contributors Team RDS Open Source Databases Amazon Web Services: https://aws.amazon.com
>From 619d4fea1eada6fb65fec673bc9600f8502f9b00 Mon Sep 17 00:00:00 2001 From: Bertrand Drouvot <bertranddrouvot...@gmail.com> Date: Wed, 7 Aug 2024 05:04:10 +0000 Subject: [PATCH v6] vaccum_delay with absolute time nanosleep --- src/backend/commands/vacuum.c | 47 +++++++++++++++++++++++++++- src/include/portability/instr_time.h | 10 ++++++ 2 files changed, 56 insertions(+), 1 deletion(-) 81.6% src/backend/commands/ 18.3% src/include/portability/ diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 48f8eab202..0ed188a083 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -116,6 +116,51 @@ static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params, static double compute_parallel_delay(void); static VacOptValue get_vacoptval_from_boolean(DefElem *def); static bool vac_tid_reaped(ItemPointer itemptr, void *state); +static void vacuum_sleep(double msec); + +static +void +vacuum_sleep(double msec) +{ + long microsec = msec * 1000; + + if (microsec > 0) + { +#ifndef WIN32 + /* + * We allow nanosleep to handle interrupts and retry with the + * remaining time. However, frequent interruptions and restarts of the + * nanosleep calls can substantially lead to drift in the time when + * the sleep finally completes. To deal with this, we break out of the + * loop whenever the current time is past the expected end time of the + * sleep. + */ + struct timespec delay; + struct timespec remain; + instr_time end_time; + + INSTR_TIME_SET_CURRENT(end_time); + INSTR_TIME_ADD_MICROSEC(end_time, microsec); + + delay.tv_sec = microsec / 1000000L; + delay.tv_nsec = (microsec % 1000000L) * 1000; + + while (nanosleep(&delay, &remain) == -1 && errno == EINTR) + { + instr_time current_time; + + INSTR_TIME_SET_CURRENT(current_time); + + if (INSTR_TIME_IS_GREATER(current_time, end_time)) + break; + + delay = remain; + } +#else + SleepEx((microsec < 500 ? 1 : (microsec + 500) / 1000), FALSE); +#endif + } +} /* * GUC check function to ensure GUC value specified is within the allowable @@ -2384,7 +2429,7 @@ vacuum_delay_point(void) msec = vacuum_cost_delay * 4; pgstat_report_wait_start(WAIT_EVENT_VACUUM_DELAY); - pg_usleep(msec * 1000); + vacuum_sleep(msec); pgstat_report_wait_end(); /* diff --git a/src/include/portability/instr_time.h b/src/include/portability/instr_time.h index e66ecf34cd..754ea77c43 100644 --- a/src/include/portability/instr_time.h +++ b/src/include/portability/instr_time.h @@ -36,6 +36,10 @@ * * INSTR_TIME_GET_NANOSEC(t) convert t to int64 (in nanoseconds) * + * INSTR_TIME_ADD_MICROSEC(x,t) add t (in microseconds) to x + * + * INSTR_TIME_IS_GREATER(x,y) is x greater than y? + * * Note that INSTR_TIME_SUBTRACT and INSTR_TIME_ACCUM_DIFF convert * absolute times to intervals. The INSTR_TIME_GET_xxx operations are * only useful on intervals. @@ -194,4 +198,10 @@ GetTimerFrequency(void) #define INSTR_TIME_GET_MICROSEC(t) \ (INSTR_TIME_GET_NANOSEC(t) / NS_PER_US) +#define INSTR_TIME_ADD_MICROSEC(x,t) \ + ((x).ticks += t * NS_PER_US) + +#define INSTR_TIME_IS_GREATER(x,y) \ + ((x).ticks > (y).ticks) + #endif /* INSTR_TIME_H */ -- 2.34.1