From 033273772ecd180f6686ae79ef861f784684822e Mon Sep 17 00:00:00 2001
From: Sami Imseih <simseih@amazon.com>
Date: Mon, 5 Aug 2024 14:38:24 -0500
Subject: [PATCH v4 1/1] vaccum_delay with absolute time nanosleep

---
 src/backend/commands/vacuum.c        | 47 +++++++++++++++++++++++++++-
 src/include/portability/instr_time.h |  6 ++++
 2 files changed, 52 insertions(+), 1 deletion(-)

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 a6fc1922f2..36f136b08f 100644
--- a/src/include/portability/instr_time.h
+++ b/src/include/portability/instr_time.h
@@ -194,4 +194,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) \
+	((bool) (x).ticks > (y).ticks)
+
 #endif							/* INSTR_TIME_H */
-- 
2.39.3 (Apple Git-146)

