From 7c3c4cc47eb0916d7aa6334df952a9c284cab2fa Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Tue, 25 Feb 2020 16:58:56 +0900
Subject: [PATCH 2/2] Fix process title update during recovery conflicts

---
 src/backend/storage/ipc/standby.c | 105 +++++++++++++++++++++---------
 1 file changed, 73 insertions(+), 32 deletions(-)

diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index c85def7317..b45a83c54c 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -48,6 +48,7 @@ static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlis
 static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason);
 static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts);
 static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks);
+static char *set_process_title_waiting(void);
 
 /*
  * Keep track of all the locks owned by a given transaction.
@@ -218,40 +219,15 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
 									   ProcSignalReason reason,
 									   uint32 wait_event_info)
 {
-	TimestampTz waitStart;
-	char	   *new_status;
-
 	/* Fast exit, to avoid a kernel call if there's no work to be done. */
 	if (!VirtualTransactionIdIsValid(*waitlist))
 		return;
 
-	waitStart = GetCurrentTimestamp();
-	new_status = NULL;			/* we haven't changed the ps display */
-
 	while (VirtualTransactionIdIsValid(*waitlist))
 	{
 		/* wait until the virtual xid is gone */
 		while (!VirtualXactLock(*waitlist, false))
 		{
-			/*
-			 * Report via ps if we have been waiting for more than 500 msec
-			 * (should that be configurable?)
-			 */
-			if (update_process_title && new_status == NULL &&
-				TimestampDifferenceExceeds(waitStart, GetCurrentTimestamp(),
-										   500))
-			{
-				const char *old_status;
-				int			len;
-
-				old_status = get_ps_display(&len);
-				new_status = (char *) palloc(len + 8 + 1);
-				memcpy(new_status, old_status, len);
-				strcpy(new_status + len, " waiting");
-				set_ps_display(new_status, false);
-				new_status[len] = '\0'; /* truncate off " waiting" */
-			}
-
 			/* Is it time to kill it? */
 			if (WaitExceedsMaxStandbyDelay(wait_event_info))
 			{
@@ -275,19 +251,13 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
 		/* The virtual transaction is gone now, wait for the next one */
 		waitlist++;
 	}
-
-	/* Reset ps display if we changed it */
-	if (new_status)
-	{
-		set_ps_display(new_status, false);
-		pfree(new_status);
-	}
 }
 
 void
 ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode node)
 {
 	VirtualTransactionId *backends;
+	char		*new_status = NULL;
 
 	/*
 	 * If we get passed InvalidTransactionId then we are a little surprised,
@@ -301,18 +271,32 @@ ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode
 	if (!TransactionIdIsValid(latestRemovedXid))
 		return;
 
+	/* Report via ps we are waiting */
+	new_status = set_process_title_waiting();
+
 	backends = GetConflictingVirtualXIDs(latestRemovedXid,
 										 node.dbNode);
 
 	ResolveRecoveryConflictWithVirtualXIDs(backends,
 										   PROCSIG_RECOVERY_CONFLICT_SNAPSHOT,
 										   PG_WAIT_LOCK | LOCKTAG_TRANSACTION);
+
+	/* Reset ps display if we changed it */
+	if (new_status)
+	{
+		set_ps_display(new_status, false);
+		pfree(new_status);
+	}
 }
 
 void
 ResolveRecoveryConflictWithTablespace(Oid tsid)
 {
 	VirtualTransactionId *temp_file_users;
+	char		*new_status = NULL;
+
+	/* Report via ps we are waiting */
+	new_status = set_process_title_waiting();
 
 	/*
 	 * Standby users may be currently using this tablespace for their
@@ -336,11 +320,23 @@ ResolveRecoveryConflictWithTablespace(Oid tsid)
 	ResolveRecoveryConflictWithVirtualXIDs(temp_file_users,
 										   PROCSIG_RECOVERY_CONFLICT_TABLESPACE,
 										   PG_WAIT_LOCK | LOCKTAG_TRANSACTION);
+
+	/* Reset ps display if we changed it */
+	if (new_status)
+	{
+		set_ps_display(new_status, false);
+		pfree(new_status);
+	}
 }
 
 void
 ResolveRecoveryConflictWithDatabase(Oid dbid)
 {
+	char		*new_status = NULL;
+
+	/* Report via ps we are waiting */
+	new_status = set_process_title_waiting();
+
 	/*
 	 * We don't do ResolveRecoveryConflictWithVirtualXIDs() here since that
 	 * only waits for transactions and completely idle sessions would block
@@ -362,6 +358,13 @@ ResolveRecoveryConflictWithDatabase(Oid dbid)
 		 */
 		pg_usleep(10000);
 	}
+
+	/* Reset ps display if we changed it */
+	if (new_status)
+	{
+		set_ps_display(new_status, false);
+		pfree(new_status);
+	}
 }
 
 /*
@@ -380,6 +383,9 @@ ResolveRecoveryConflictWithDatabase(Oid dbid)
  *
  * Deadlocks involving the Startup process and an ordinary backend process
  * will be detected by the deadlock detector within the ordinary backend.
+ *
+ * Unlike other recovery conflict resolution functions, this function
+ * doesn't update the process title since we have already updated it.
  */
 void
 ResolveRecoveryConflictWithLock(LOCKTAG locktag)
@@ -458,9 +464,13 @@ void
 ResolveRecoveryConflictWithBufferPin(void)
 {
 	TimestampTz ltime;
+	char		*new_status = NULL;
 
 	Assert(InHotStandby);
 
+	/* Report via ps we are waiting */
+	new_status = set_process_title_waiting();
+
 	ltime = GetStandbyLimitTime();
 
 	if (ltime == 0)
@@ -505,6 +515,13 @@ ResolveRecoveryConflictWithBufferPin(void)
 	 * individually, but that'd be slower.
 	 */
 	disable_all_timeouts(false);
+
+	/* Reset ps display if we changed it */
+	if (new_status)
+	{
+		set_ps_display(new_status, false);
+		pfree(new_status);
+	}
 }
 
 static void
@@ -1091,3 +1108,27 @@ LogStandbyInvalidations(int nmsgs, SharedInvalidationMessage *msgs,
 					 nmsgs * sizeof(SharedInvalidationMessage));
 	XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS);
 }
+
+/*
+ * Add " waiting" to the process title, and return palloc'd
+ * original process title.
+ */
+static char *
+set_process_title_waiting(void)
+{
+	const char	*old_status;
+	char		*ret_status;
+	int			len;
+
+	if (!update_process_title)
+		return NULL;
+
+	old_status = get_ps_display(&len);
+	ret_status = (char *) palloc(len + 8 + 1);
+	memcpy(ret_status, old_status, len);
+	strcpy(ret_status + len, " waiting");
+	set_ps_display(ret_status, false);
+	ret_status[len] = '\0'; /* truncate off " waiting" */
+
+	return ret_status;
+}
-- 
2.23.0

