From f77cf0f831df74e5e2d11910cea395f5f4541d25 Mon Sep 17 00:00:00 2001
From: Sami Imseih <samimseih@gmail.com>
Date: Thu, 25 Jul 2024 20:28:35 +0000
Subject: [PATCH 1/1] vaccum_delay with absolute time nanosleep

---
 src/backend/commands/vacuum.c | 49 ++++++++++++++++++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)

diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 48f8eab202..a753d6984f 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -116,6 +116,53 @@ 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 elapsed time exceeds the requested time.
+		 */
+		struct timespec delay;
+		struct timespec remain;
+		struct instr_time start_time;
+
+		INSTR_TIME_SET_CURRENT(start_time);
+
+		delay.tv_sec = microsec / 1000000L;
+		delay.tv_nsec = (microsec % 1000000L) * 1000;
+
+		while (nanosleep(&delay, &remain) == -1 && errno == EINTR)
+		{
+			struct instr_time current_time;
+			struct instr_time elapsed_time;
+
+			INSTR_TIME_SET_CURRENT(current_time);
+
+			INSTR_TIME_SET_ZERO(elapsed_time);
+			INSTR_TIME_ACCUM_DIFF(elapsed_time, current_time, start_time);
+
+			if (INSTR_TIME_GET_MICROSEC(elapsed_time) >= microsec)
+				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 +2431,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();
 
 		/*
-- 
2.43.0

