From abfa974be88a5b3fb10144873aeca2679e4e95ff Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 28 Jan 2022 08:17:27 +0000
Subject: [PATCH v3] 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 | 28 ++++++++++++++++++++++---
 src/bin/pg_controldata/pg_controldata.c | 19 +++++++++++++++++
 src/include/catalog/pg_control.h        |  5 +++--
 src/include/catalog/pg_proc.dat         |  6 +++---
 6 files changed, 57 insertions(+), 8 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..0640a450e1 100644
--- a/src/backend/utils/misc/pg_controldata.c
+++ b/src/backend/utils/misc/pg_controldata.c
@@ -79,20 +79,23 @@ 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;
+#define	CHECKPOINT_KIND_TEXT_LENGTH 128
+	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 +132,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,9 +207,26 @@ 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));
+#undef CHECKPOINT_KIND_TEXT_LENGTH
 }
 
 Datum
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index f911f98d94..37c1ebf8ad 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -106,6 +106,9 @@ main(int argc, char *argv[])
 	int			c;
 	int			i;
 	int			WalSegSz;
+	uint16		flags;
+#define	CHECKPOINT_KIND_TEXT_LENGTH 128
+	char 		ckpt_kind[CHECKPOINT_KIND_TEXT_LENGTH];
 
 	pg_logging_init(argv[0]);
 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_controldata"));
@@ -225,6 +228,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 +251,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"),
@@ -329,4 +347,5 @@ main(int argc, char *argv[])
 	printf(_("Mock authentication nonce:            %s\n"),
 		   mock_auth_nonce_str);
 	return 0;
+#undef CHECKPOINT_KIND_TEXT_LENGTH
 }
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..4ec24ff518 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -128,9 +128,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

