From d46275236c8c3c2573d58c9d0214b11f71909f02 Mon Sep 17 00:00:00 2001
From: krisdiano <litianxiang01@gmail.com>
Date: Thu, 2 Nov 2023 13:16:36 +0800
Subject: [PATCH] Make pg_ctl more friendly for users

Utility pg_basebackup could generate a standby datadir. Before startup, setting
recovery_target_action to shutdown. Maybe users get a failure message after startup.

Now, postmaster will generate a recovery.done file if startup process exits with
code 3. Utility pg_ctl check whether the file exists or not.
---
 src/backend/access/transam/xlogrecovery.c |  1 -
 src/backend/postmaster/postmaster.c       | 17 ++++++++++++++++
 src/bin/pg_ctl/pg_ctl.c                   | 24 +++++++++++++++++++++--
 src/include/access/transam.h              |  4 ++++
 src/include/access/xlog.h                 |  2 +-
 src/include/catalog/pg_database.dat       |  9 +++++----
 src/include/utils/wait_event.h            |  2 +-
 src/tools/pgindent/typedefs.list          | 14 ++++++-------
 8 files changed, 56 insertions(+), 17 deletions(-)

diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index c61566666a..412cdf13dd 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -66,7 +66,6 @@
 
 /* Unsupported old recovery command file names (relative to $PGDATA) */
 #define RECOVERY_COMMAND_FILE	"recovery.conf"
-#define RECOVERY_COMMAND_DONE	"recovery.done"
 
 /*
  * GUC support
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 7b6b613c4a..0ca13ee743 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -2936,6 +2936,23 @@ process_pm_child_exit(void)
 				Shutdown = Max(Shutdown, SmartShutdown);
 				TerminateChildren(SIGTERM);
 				pmState = PM_WAIT_BACKENDS;
+
+				/*
+				 * This file gives a tip to pg_ctl which could provide a more
+				 * friendly message to users.
+				 */
+				PG_TRY();
+				{
+					FILE	   *fp = AllocateFile(RECOVERY_COMMAND_DONE, PG_BINARY_W);
+
+					FreeFile(fp);
+				}
+				PG_CATCH();
+				{
+					/* Ignore errors, it just best errort */
+				}
+				PG_END_TRY();
+
 				/* PostmasterStateMachine logic does the rest */
 				continue;
 			}
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 3b145bd838..d9ab12ab85 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -15,12 +15,14 @@
 #include <signal.h>
 #include <time.h>
 #include <sys/resource.h>
+#include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
 
+#include "access/transam.h"
 #include "catalog/pg_control.h"
 #include "common/controldata_utils.h"
 #include "common/file_perm.h"
@@ -46,6 +48,7 @@ typedef enum
 	POSTMASTER_READY,
 	POSTMASTER_STILL_STARTING,
 	POSTMASTER_FAILED,
+	POSTMASTER_RECOVERY_SHUTDOWN,
 } WaitPMResult;
 
 typedef enum
@@ -98,6 +101,7 @@ static char version_file[MAXPGPATH];
 static char pid_file[MAXPGPATH];
 static char promote_file[MAXPGPATH];
 static char logrotate_file[MAXPGPATH];
+static char recovery_done_file[MAXPGPATH];
 
 static volatile pid_t postmasterPID = -1;
 
@@ -572,6 +576,17 @@ start_postmaster(void)
 #endif							/* WIN32 */
 }
 
+static bool
+has_recovery_done_file()
+{
+
+	struct stat statbuf;
+	int			errcode;
+
+	errcode = stat(recovery_done_file, &statbuf);
+	return errcode == 0 || errno == EACCES;
+
+}
 
 
 /*
@@ -662,11 +677,11 @@ wait_for_postmaster_start(pid_t pm_pid, bool do_checkpoint)
 			int			exitstatus;
 
 			if (waitpid(pm_pid, &exitstatus, WNOHANG) == pm_pid)
-				return POSTMASTER_FAILED;
+				return has_recovery_done_file() ? POSTMASTER_RECOVERY_SHUTDOWN : POSTMASTER_FAILED;
 		}
 #else
 		if (WaitForSingleObject(postmasterProcess, 0) == WAIT_OBJECT_0)
-			return POSTMASTER_FAILED;
+			return has_recovery_done_file() ? POSTMASTER_RECOVERY_SHUTDOWN : POSTMASTER_FAILED;
 #endif
 
 		/* Startup still in process; wait, printing a dot once per second */
@@ -985,6 +1000,10 @@ do_start(void)
 				print_msg(_(" done\n"));
 				print_msg(_("server started\n"));
 				break;
+			case POSTMASTER_RECOVERY_SHUTDOWN:
+				print_msg(_("PITR shutdown\n"));
+				print_msg(_("update configuration for startup again if needed\n"));
+				break;
 			case POSTMASTER_STILL_STARTING:
 				print_msg(_(" stopped waiting\n"));
 				write_stderr(_("%s: server did not start in time\n"),
@@ -2446,6 +2465,7 @@ main(int argc, char **argv)
 		snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
 		snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", pg_data);
 		snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
+		snprintf(recovery_done_file, MAXPGPATH, "%s/%s", pg_data, RECOVERY_COMMAND_DONE);
 
 		/*
 		 * Set mask based on PGDATA permissions,
diff --git a/src/include/access/transam.h b/src/include/access/transam.h
index f5af6d3055..4ab41a6860 100644
--- a/src/include/access/transam.h
+++ b/src/include/access/transam.h
@@ -257,6 +257,10 @@ typedef struct VariableCacheData
 typedef VariableCacheData *VariableCache;
 
 
+/* This file are generated when PITR shutdown */
+#define RECOVERY_COMMAND_DONE	"recovery.done"
+
+
 /* ----------------
  *		extern declarations
  * ----------------
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index a14126d164..cb8d127d5f 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -26,7 +26,7 @@ typedef enum WalSyncMethod
 	WAL_SYNC_METHOD_OPEN,		/* for O_SYNC */
 	WAL_SYNC_METHOD_FSYNC_WRITETHROUGH,
 	WAL_SYNC_METHOD_OPEN_DSYNC	/* for O_DSYNC */
-} WalSyncMethod;
+}			WalSyncMethod;
 extern PGDLLIMPORT int wal_sync_method;
 
 extern PGDLLIMPORT XLogRecPtr ProcLastRecPtr;
diff --git a/src/include/catalog/pg_database.dat b/src/include/catalog/pg_database.dat
index 8d91e3bf8d..3057f1a230 100644
--- a/src/include/catalog/pg_database.dat
+++ b/src/include/catalog/pg_database.dat
@@ -16,9 +16,10 @@
   descr => 'default template for new databases',
   datname => 'template1', encoding => 'ENCODING',
   datlocprovider => 'LOCALE_PROVIDER', datistemplate => 't',
-  datallowconn => 't', dathasloginevt => 'f', datconnlimit => '-1', datfrozenxid => '0',
-  datminmxid => '1', dattablespace => 'pg_default', datcollate => 'LC_COLLATE',
-  datctype => 'LC_CTYPE', daticulocale => 'ICU_LOCALE',
-  daticurules => 'ICU_RULES', datacl => '_null_' },
+  datallowconn => 't', dathasloginevt => 'f', datconnlimit => '-1',
+  datfrozenxid => '0', datminmxid => '1', dattablespace => 'pg_default',
+  datcollate => 'LC_COLLATE', datctype => 'LC_CTYPE',
+  daticulocale => 'ICU_LOCALE', daticurules => 'ICU_RULES',
+  datacl => '_null_' },
 
 ]
diff --git a/src/include/utils/wait_event.h b/src/include/utils/wait_event.h
index 00f7d620e7..9d89e87195 100644
--- a/src/include/utils/wait_event.h
+++ b/src/include/utils/wait_event.h
@@ -57,7 +57,7 @@ typedef enum
 {
 	WAIT_EVENT_EXTENSION = PG_WAIT_EXTENSION,
 	WAIT_EVENT_EXTENSION_FIRST_USER_DEFINED,
-} WaitEventExtension;
+}			WaitEventExtension;
 
 extern void WaitEventExtensionShmemInit(void);
 extern Size WaitEventExtensionShmemSize(void);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 87c1aee379..c0749e4df9 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -367,7 +367,6 @@ CatalogId
 CatalogIdMapEntry
 CatalogIndexState
 ChangeVarNodes_context
-ReplaceVarnoContext
 CheckPoint
 CheckPointStmt
 CheckpointStatsData
@@ -1276,9 +1275,9 @@ JsonManifestWALRangeField
 JsonObjectAgg
 JsonObjectConstructor
 JsonOutput
-JsonParseExpr
 JsonParseContext
 JsonParseErrorType
+JsonParseExpr
 JsonPath
 JsonPathBool
 JsonPathExecContext
@@ -1341,6 +1340,7 @@ LINE
 LLVMAttributeRef
 LLVMBasicBlockRef
 LLVMBuilderRef
+LLVMContextRef
 LLVMErrorRef
 LLVMIntPredicate
 LLVMJITEventListenerRef
@@ -1916,7 +1916,6 @@ ParallelHashJoinBatch
 ParallelHashJoinBatchAccessor
 ParallelHashJoinState
 ParallelIndexScanDesc
-ParallelReadyList
 ParallelSlot
 ParallelSlotArray
 ParallelSlotResultHandler
@@ -2343,6 +2342,7 @@ ReorderBufferUpdateProgressTxnCB
 ReorderTuple
 RepOriginId
 ReparameterizeForeignPathByChild_function
+ReplaceVarnoContext
 ReplaceVarsFromTargetList_context
 ReplaceVarsNoMatchOption
 ReplicaIdentityStmt
@@ -2919,6 +2919,7 @@ UnicodeNormalizationQC
 Unique
 UniquePath
 UniquePathMethod
+UniqueRelInfo
 UniqueState
 UnlistenStmt
 UnresolvedTup
@@ -2975,7 +2976,6 @@ VolatileFunctionStatus
 Vsrt
 WAIT_ORDER
 WALAvailability
-WalInsertClass
 WALInsertLock
 WALInsertLockPadded
 WALOpenSegment
@@ -2997,7 +2997,6 @@ WaitEvent
 WaitEventActivity
 WaitEventBufferPin
 WaitEventClient
-WaitEventExtension
 WaitEventExtensionCounterData
 WaitEventExtensionEntryById
 WaitEventExtensionEntryByName
@@ -3008,6 +3007,7 @@ WaitEventTimeout
 WaitPMResult
 WalCloseMethod
 WalCompression
+WalInsertClass
 WalLevel
 WalRcvData
 WalRcvExecResult
@@ -3021,7 +3021,6 @@ WalSnd
 WalSndCtlData
 WalSndSendDataCallback
 WalSndState
-WalSyncMethod
 WalTimeSample
 WalUsage
 WalWriteMethod
@@ -3407,6 +3406,7 @@ indexed_tlist
 inet
 inetKEY
 inet_struct
+initRowMethod
 init_function
 inline_cte_walker_context
 inline_error_callback_arg
@@ -3839,7 +3839,6 @@ unicodeStyleColumnFormat
 unicodeStyleFormat
 unicodeStyleRowFormat
 unicode_linestyle
-UniqueRelInfo
 unit_conversion
 unlogged_relation_entry
 utf_local_conversion_func
@@ -3875,7 +3874,6 @@ wchar2mb_with_len_converter
 wchar_t
 win32_deadchild_waitinfo
 wint_t
-worker_spi_state
 worker_state
 worktable
 wrap
-- 
2.30.1

