On Thu, Apr 15, 2021 at 11:48 AM Bharath Rupireddy
<bharath.rupireddyforpostg...@gmail.com> wrote:
> > We definitely have replaced a lot of sleeps with latch.c primitives
> > over the past few years, since we got WL_EXIT_ON_PM_DEATH and
> > condition variables.  There may be many more to improve...  You
> > mentioned autovacuum... yeah, Stephen fixed one of these with commit
> > 4753ef37, but yeah it's not great to have those others in there...
>
> I have not looked at the commit 4753ef37 previously, but it
> essentially addresses the problem with pg_usleep for vacuum delay. I'm
> thinking we can also replace pg_usleep in below places based on the
> fact that pg_usleep should be avoided in 1) short waits in a loop 2)
> when wait time is dependent on user configurable parameters. And using
> WaitLatch may require us to add wait event types to WaitEventTimeout
> enum, but that's okay.

I'm attaching 3 patches that replace pg_usleep with WaitLatch: 0001 in
lazy_truncate_heap, 0002 in do_pg_stop_backup and 0003 for Pre and
Post Auth Delay. Regression tests pass with these patches. Please
review them.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com
From 4cd54df7e27efb5dd82751fd8c7d15c475ce4a40 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Mon, 19 Apr 2021 19:25:02 +0530
Subject: [PATCH v1] Use a WaitLatch for lock waiting in lazy_truncate_heap

Instead of using pg_usleep() in lazy_truncate_heap(), use a
WaitLatch. This has the advantage that we will realize if the
postmaster has been killed since the last time we decided to
sleep.
---
 doc/src/sgml/monitoring.sgml            | 5 +++++
 src/backend/access/heap/vacuumlazy.c    | 6 +++++-
 src/backend/utils/activity/wait_event.c | 3 +++
 src/include/utils/wait_event.h          | 3 ++-
 4 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 5cf083bb77..65d51ce445 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2249,6 +2249,11 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <entry><literal>VacuumDelay</literal></entry>
       <entry>Waiting in a cost-based vacuum delay point.</entry>
      </row>
+     <row>
+      <entry><literal>VacuumTruncateLock</literal></entry>
+      <entry>Waiting to acquire exclusive lock on relation for truncation while
+      vacuuming.</entry>
+     </row>
     </tbody>
    </tgroup>
   </table>
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index e90fc18aa9..dcd598fca8 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -3188,7 +3188,11 @@ lazy_truncate_heap(LVRelState *vacrel)
 				return;
 			}
 
-			pg_usleep(VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL * 1000L);
+			(void) WaitLatch(MyLatch,
+							 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+							 VACUUM_TRUNCATE_LOCK_WAIT_INTERVAL,
+							 WAIT_EVENT_VACUUM_TRUNCATE_LOCK);
+			ResetLatch(MyLatch);
 		}
 
 		/*
diff --git a/src/backend/utils/activity/wait_event.c b/src/backend/utils/activity/wait_event.c
index 89b5b8b7b9..694cd48315 100644
--- a/src/backend/utils/activity/wait_event.c
+++ b/src/backend/utils/activity/wait_event.c
@@ -485,6 +485,9 @@ pgstat_get_wait_timeout(WaitEventTimeout w)
 		case WAIT_EVENT_VACUUM_DELAY:
 			event_name = "VacuumDelay";
 			break;
+		case WAIT_EVENT_VACUUM_TRUNCATE_LOCK:
+			event_name = "VacuumTruncateLock";
+			break;
 			/* no default case, so that compiler will warn */
 	}
 
diff --git a/src/include/utils/wait_event.h b/src/include/utils/wait_event.h
index 47accc5ffe..60b8ca76f7 100644
--- a/src/include/utils/wait_event.h
+++ b/src/include/utils/wait_event.h
@@ -140,7 +140,8 @@ typedef enum
 	WAIT_EVENT_PG_SLEEP,
 	WAIT_EVENT_RECOVERY_APPLY_DELAY,
 	WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL,
-	WAIT_EVENT_VACUUM_DELAY
+	WAIT_EVENT_VACUUM_DELAY,
+	WAIT_EVENT_VACUUM_TRUNCATE_LOCK
 } WaitEventTimeout;
 
 /* ----------
-- 
2.25.1

From cf38b83a8c224bce7db730fe3a18ec897690f8ae Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Tue, 20 Apr 2021 06:18:15 +0530
Subject: [PATCH v1] Use a WaitLatch in do_pg_stop_backup

Instead of using pg_usleep() in do_pg_stop_backup(), use a
WaitLatch. This has the advantage that we will realize if the
postmaster has been killed since the last time we decided to
sleep.
---
 src/backend/access/transam/xlog.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index adfc6f67e2..a632a46a57 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -11605,6 +11605,8 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
 		((!backup_started_in_recovery && XLogArchivingActive()) ||
 		 (backup_started_in_recovery && XLogArchivingAlways())))
 	{
+		Latch *latch;
+
 		XLByteToPrevSeg(stoppoint, _logSegNo, wal_segment_size);
 		XLogFileName(lastxlogfilename, stoptli, _logSegNo, wal_segment_size);
 
@@ -11615,6 +11617,11 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
 		seconds_before_warning = 60;
 		waits = 0;
 
+		if (backup_started_in_recovery)
+			latch = &XLogCtl->recoveryWakeupLatch;
+		else
+			latch = MyLatch;
+
 		while (XLogArchiveIsBusy(lastxlogfilename) ||
 			   XLogArchiveIsBusy(histfilename))
 		{
@@ -11627,9 +11634,11 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
 				reported_waiting = true;
 			}
 
-			pgstat_report_wait_start(WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE);
-			pg_usleep(1000000L);
-			pgstat_report_wait_end();
+			(void) WaitLatch(latch,
+							 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+							 1000L,
+							 WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE);
+			ResetLatch(latch);
 
 			if (++waits >= seconds_before_warning)
 			{
-- 
2.25.1

From e89fcae1267d1b508a7891df48efc8f8a48cf74e Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Mon, 19 Apr 2021 19:27:53 +0530
Subject: [PATCH v1] Use a WaitLatch for Pre and Post Auth Delay

Instead of using pg_usleep() for waiting PostAuthDelay and
PreAuthDelay, use a WaitLatch. This has the advantage that
we will realize if the postmaster has been killed since the
last time we decided to sleep.
---
 doc/src/sgml/monitoring.sgml            | 10 ++++++++++
 src/backend/postmaster/autovacuum.c     | 18 ++++++++++++++++--
 src/backend/postmaster/bgworker.c       |  8 +++++++-
 src/backend/postmaster/postmaster.c     |  8 +++++++-
 src/backend/utils/activity/wait_event.c |  6 ++++++
 src/backend/utils/init/postinit.c       | 16 ++++++++++++++--
 src/include/utils/wait_event.h          |  2 ++
 7 files changed, 62 insertions(+), 6 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 65d51ce445..22208e1b6d 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2235,6 +2235,16 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       <entry>Waiting due to a call to <function>pg_sleep</function> or
        a sibling function.</entry>
      </row>
+     <row>
+      <entry><literal>PostAuthDelay</literal></entry>
+      <entry>Waiting on connection startup after authentication to allow attach
+      from a debugger.</entry>
+     </row>
+     <row>
+      <entry><literal>PreAuthDelay</literal></entry>
+      <entry>Waiting on connection startup before authentication to allow
+      attach from a debugger.</entry>
+     </row>
      <row>
       <entry><literal>RecoveryApplyDelay</literal></entry>
       <entry>Waiting to apply WAL during recovery because of a delay
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 83c584ddc8..f5669ef227 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -446,8 +446,15 @@ AutoVacLauncherMain(int argc, char *argv[])
 	ereport(DEBUG1,
 			(errmsg_internal("autovacuum launcher started")));
 
+	/* Apply PostAuthDelay */
 	if (PostAuthDelay)
-		pg_usleep(PostAuthDelay * 1000000L);
+	{
+		(void) WaitLatch(MyLatch,
+						 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+						 PostAuthDelay * 1000L,
+						 WAIT_EVENT_POST_AUTH_DELAY);
+		ResetLatch(MyLatch);
+	}
 
 	SetProcessingMode(InitProcessing);
 
@@ -1706,8 +1713,15 @@ AutoVacWorkerMain(int argc, char *argv[])
 		ereport(DEBUG1,
 				(errmsg_internal("autovacuum: processing database \"%s\"", dbname)));
 
+		/* Apply PostAuthDelay */
 		if (PostAuthDelay)
-			pg_usleep(PostAuthDelay * 1000000L);
+		{
+			(void) WaitLatch(MyLatch,
+							 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+							 PostAuthDelay * 1000L,
+							 WAIT_EVENT_POST_AUTH_DELAY);
+			ResetLatch(MyLatch);
+		}
 
 		/* And do an appropriate amount of work */
 		recentXid = ReadNextTransactionId();
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index 11fc1b7863..3fa703c3f8 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -752,7 +752,13 @@ StartBackgroundWorker(void)
 
 	/* Apply PostAuthDelay */
 	if (PostAuthDelay > 0)
-		pg_usleep(PostAuthDelay * 1000000L);
+	{
+		(void) WaitLatch(MyLatch,
+						 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+						 PostAuthDelay * 1000L,
+						 WAIT_EVENT_POST_AUTH_DELAY);
+		ResetLatch(MyLatch);
+	}
 
 	/*
 	 * Set up signal handlers.
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index b05db5a473..da019e6c5e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -4313,7 +4313,13 @@ BackendInitialize(Port *port)
 	 * is not honored until after authentication.)
 	 */
 	if (PreAuthDelay > 0)
-		pg_usleep(PreAuthDelay * 1000000L);
+	{
+		(void) WaitLatch(MyLatch,
+						 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+						 PostAuthDelay * 1000L,
+						 WAIT_EVENT_PRE_AUTH_DELAY);
+		ResetLatch(MyLatch);
+	}
 
 	/* This flag will remain set until InitPostgres finishes authentication */
 	ClientAuthInProgress = true;	/* limit visibility of log messages */
diff --git a/src/backend/utils/activity/wait_event.c b/src/backend/utils/activity/wait_event.c
index 694cd48315..780f0cde73 100644
--- a/src/backend/utils/activity/wait_event.c
+++ b/src/backend/utils/activity/wait_event.c
@@ -476,6 +476,12 @@ pgstat_get_wait_timeout(WaitEventTimeout w)
 		case WAIT_EVENT_PG_SLEEP:
 			event_name = "PgSleep";
 			break;
+		case WAIT_EVENT_POST_AUTH_DELAY:
+			event_name = "PostAuthDelay";
+			break;
+		case WAIT_EVENT_PRE_AUTH_DELAY:
+			event_name = "PreAuthDelay";
+			break;
 		case WAIT_EVENT_RECOVERY_APPLY_DELAY:
 			event_name = "RecoveryApplyDelay";
 			break;
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 51d1bbef30..2a48fd4d5b 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -849,7 +849,13 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 
 		/* Apply PostAuthDelay as soon as we've read all options */
 		if (PostAuthDelay > 0)
-			pg_usleep(PostAuthDelay * 1000000L);
+		{
+			(void) WaitLatch(MyLatch,
+							 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+							 PostAuthDelay * 1000L,
+							 WAIT_EVENT_POST_AUTH_DELAY);
+			ResetLatch(MyLatch);
+		}
 
 		/* initialize client encoding */
 		InitializeClientEncoding();
@@ -1055,7 +1061,13 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 
 	/* Apply PostAuthDelay as soon as we've read all options */
 	if (PostAuthDelay > 0)
-		pg_usleep(PostAuthDelay * 1000000L);
+	{
+		(void) WaitLatch(MyLatch,
+						 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
+						 PostAuthDelay * 1000L,
+						 WAIT_EVENT_POST_AUTH_DELAY);
+		ResetLatch(MyLatch);
+	}
 
 	/*
 	 * Initialize various default states that can't be set up until we've
diff --git a/src/include/utils/wait_event.h b/src/include/utils/wait_event.h
index 60b8ca76f7..024ed8cc07 100644
--- a/src/include/utils/wait_event.h
+++ b/src/include/utils/wait_event.h
@@ -138,6 +138,8 @@ typedef enum
 {
 	WAIT_EVENT_BASE_BACKUP_THROTTLE = PG_WAIT_TIMEOUT,
 	WAIT_EVENT_PG_SLEEP,
+	WAIT_EVENT_POST_AUTH_DELAY,
+	WAIT_EVENT_PRE_AUTH_DELAY,
 	WAIT_EVENT_RECOVERY_APPLY_DELAY,
 	WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL,
 	WAIT_EVENT_VACUUM_DELAY,
-- 
2.25.1

Reply via email to