From e118edc5852434847dac36c566e7feca6f1f22ca Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 28 Jan 2022 14:30:18 +0000
Subject: [PATCH v4] add last checkpoint kind to pg_control file

Bump catalog version
---
 doc/src/sgml/func.sgml                  |  5 +++++
 src/backend/access/transam/xlog.c       |  2 ++
 src/backend/utils/misc/pg_controldata.c | 26 ++++++++++++++++++++++---
 src/bin/pg_controldata/pg_controldata.c | 17 ++++++++++++++++
 src/include/catalog/pg_control.h        | 10 +++++++---
 src/include/catalog/pg_proc.dat         |  6 +++---
 6 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 0ee6974f1c..4357ca838e 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25093,6 +25093,11 @@ SELECT collation for ('foo' COLLATE "de_DE");
        <entry><type>timestamp with time zone</type></entry>
       </row>
 
+      <row>
+       <entry><structfield>checkpoint_kind</structfield></entry>
+       <entry><type>text</type></entry>
+      </row>
+
      </tbody>
     </tgroup>
    </table>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index dfe2a0bcce..72255f6b8a 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -9375,6 +9375,7 @@ CreateCheckPoint(int flags)
 	LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
 	if (shutdown)
 		ControlFile->state = DB_SHUTDOWNED;
+	ControlFile->checkPointKind = flags;
 	ControlFile->checkPoint = ProcLastRecPtr;
 	ControlFile->checkPointCopy = checkPoint;
 	/* crash recovery should always recover to the end of WAL */
@@ -9761,6 +9762,7 @@ CreateRestartPoint(int flags)
 	if (ControlFile->state == DB_IN_ARCHIVE_RECOVERY &&
 		ControlFile->checkPointCopy.redo < lastCheckPoint.redo)
 	{
+		ControlFile->checkPointKind = flags;
 		ControlFile->checkPoint = lastCheckPointRecPtr;
 		ControlFile->checkPointCopy = lastCheckPoint;
 
diff --git a/src/backend/utils/misc/pg_controldata.c b/src/backend/utils/misc/pg_controldata.c
index 781f8b8758..9d48a99378 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -79,20 +79,22 @@ pg_control_system(PG_FUNCTION_ARGS)
 Datum
 pg_control_checkpoint(PG_FUNCTION_ARGS)
 {
-	Datum		values[18];
-	bool		nulls[18];
+	Datum		values[19];
+	bool		nulls[19];
 	TupleDesc	tupdesc;
 	HeapTuple	htup;
 	ControlFileData *ControlFile;
 	XLogSegNo	segno;
 	char		xlogfilename[MAXFNAMELEN];
 	bool		crc_ok;
+	uint16		flags;
+	char 		ckpt_kind[CHECKPOINT_KIND_TEXT_LENGTH];
 
 	/*
 	 * Construct a tuple descriptor for the result row.  This must match this
 	 * function's pg_proc entry!
 	 */
-	tupdesc = CreateTemplateTupleDesc(18);
+	tupdesc = CreateTemplateTupleDesc(19);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "checkpoint_lsn",
 					   PG_LSNOID, -1, 0);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "redo_lsn",
@@ -129,6 +131,8 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 					   XIDOID, -1, 0);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 18, "checkpoint_time",
 					   TIMESTAMPTZOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 19, "checkpoint_kind",
+					   TEXTOID, -1, 0);
 	tupdesc = BlessTupleDesc(tupdesc);
 
 	/* Read the control file. */
@@ -202,6 +206,22 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
 	values[17] = TimestampTzGetDatum(time_t_to_timestamptz(ControlFile->checkPointCopy.time));
 	nulls[17] = false;
 
+	MemSet(ckpt_kind, 0, CHECKPOINT_KIND_TEXT_LENGTH);
+	flags = ControlFile->checkPointKind;
+
+	snprintf(ckpt_kind, CHECKPOINT_KIND_TEXT_LENGTH, "%s%s%s%s%s%s%s%s",
+				(flags & CHECKPOINT_IS_SHUTDOWN) ? "shutdown" : "",
+				(flags & CHECKPOINT_END_OF_RECOVERY) ? " end-of-recovery" : "",
+				(flags & CHECKPOINT_IMMEDIATE) ? " immediate" : "",
+				(flags & CHECKPOINT_FORCE) ? " force" : "",
+				(flags & CHECKPOINT_WAIT) ? " wait" : "",
+				(flags & CHECKPOINT_CAUSE_XLOG) ? " wal" : "",
+				(flags & CHECKPOINT_CAUSE_TIME) ? " time" : "",
+				(flags & CHECKPOINT_FLUSH_ALL) ? " flush-all" : "");
+
+	values[18] = CStringGetTextDatum(ckpt_kind);
+	nulls[18] = false;
+
 	htup = heap_form_tuple(tupdesc, values, nulls);
 
 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index f911f98d94..f378cfcda5 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -106,6 +106,8 @@ main(int argc, char *argv[])
 	int			c;
 	int			i;
 	int			WalSegSz;
+	uint16		flags;
+	char 		ckpt_kind[CHECKPOINT_KIND_TEXT_LENGTH];
 
 	pg_logging_init(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata"));
@@ -225,6 +227,19 @@ main(int argc, char *argv[])
 		snprintf(&mock_auth_nonce_str[i * 2], 3, "%02x",
 				 (unsigned char) ControlFile->mock_authentication_nonce[i]);
 
+	MemSet(ckpt_kind, 0, CHECKPOINT_KIND_TEXT_LENGTH);
+	flags = ControlFile->checkPointKind;
+
+	snprintf(ckpt_kind, CHECKPOINT_KIND_TEXT_LENGTH, "%s%s%s%s%s%s%s%s",
+				(flags & CHECKPOINT_IS_SHUTDOWN) ? "shutdown" : "",
+				(flags & CHECKPOINT_END_OF_RECOVERY) ? " end-of-recovery" : "",
+				(flags & CHECKPOINT_IMMEDIATE) ? " immediate" : "",
+				(flags & CHECKPOINT_FORCE) ? " force" : "",
+				(flags & CHECKPOINT_WAIT) ? " wait" : "",
+				(flags & CHECKPOINT_CAUSE_XLOG) ? " wal" : "",
+				(flags & CHECKPOINT_CAUSE_TIME) ? " time" : "",
+				(flags & CHECKPOINT_FLUSH_ALL) ? " flush-all" : "");
+
 	printf(_("pg_control version number:            %u\n"),
 		   ControlFile->pg_control_version);
 	printf(_("Catalog version number:               %u\n"),
@@ -235,6 +250,8 @@ main(int argc, char *argv[])
 		   dbState(ControlFile->state));
 	printf(_("pg_control last modified:             %s\n"),
 		   pgctime_str);
+	printf(_("Latest checkpoint kind:               %s\n"),
+		   ckpt_kind);
 	printf(_("Latest checkpoint location:           %X/%X\n"),
 		   LSN_FORMAT_ARGS(ControlFile->checkPoint));
 	printf(_("Latest checkpoint's REDO location:    %X/%X\n"),
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..f2209acaa1 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -22,11 +22,14 @@
 
 
 /* Version identifier for this pg_control format */
-#define PG_CONTROL_VERSION	1300
+#define PG_CONTROL_VERSION	1500
 
 /* Nonce key length, see below */
 #define MOCK_AUTH_NONCE_LEN		32
 
+/* Maximum length of checkpoint kind text */
+#define	CHECKPOINT_KIND_TEXT_LENGTH 128
+
 /*
  * Body of CheckPoint XLOG records.  This is declared here because we keep
  * a copy of the latest one in pg_control for possible disaster recovery.
@@ -128,9 +131,10 @@ typedef struct ControlFileData
 	 */
 	DBState		state;			/* see enum above */
 	pg_time_t	time;			/* time stamp of last pg_control update */
-	XLogRecPtr	checkPoint;		/* last check point record ptr */
+	uint16		checkPointKind;	/* last checkpoint kind */
+	XLogRecPtr	checkPoint;		/* last checkpoint record ptr */
 
-	CheckPoint	checkPointCopy; /* copy of last check point record */
+	CheckPoint	checkPointCopy; /* copy of last checkpoint record */
 
 	XLogRecPtr	unloggedLSN;	/* current fake LSN value, for unlogged rels */
 
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 0859dc81ca..5c0e20fe5c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -11565,9 +11565,9 @@
   descr => 'pg_controldata checkpoint state information as a function',
   proname => 'pg_control_checkpoint', provolatile => 'v',
   prorettype => 'record', proargtypes => '',
-  proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,text,oid,xid,xid,xid,oid,xid,xid,oid,xid,xid,timestamptz}',
-  proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
-  proargnames => '{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time}',
+  proallargtypes => '{pg_lsn,pg_lsn,text,int4,int4,bool,text,oid,xid,xid,xid,oid,xid,xid,oid,xid,xid,timestamptz,text}',
+  proargmodes => '{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}',
+  proargnames => '{checkpoint_lsn,redo_lsn,redo_wal_file,timeline_id,prev_timeline_id,full_page_writes,next_xid,next_oid,next_multixact_id,next_multi_offset,oldest_xid,oldest_xid_dbid,oldest_active_xid,oldest_multi_xid,oldest_multi_dbid,oldest_commit_ts_xid,newest_commit_ts_xid,checkpoint_time,checkpoint_kind}',
   prosrc => 'pg_control_checkpoint' },
 
 { oid => '3443',
-- 
2.25.1

