From 676ab7c15ccb99e4e18cb1aceef60795223ab569 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Tue, 27 Sep 2016 16:21:54 +0900
Subject: [PATCH 2/3] hs-checkpoints-v12-2

Make XLOG_SWITCH NO_PROGRESS and manage log switching LSN to avoid
excessive log switching and checkpoints.
---
 src/backend/access/transam/xlog.c     |  2 ++
 src/backend/postmaster/checkpointer.c | 40 +++++++++++++++++++++++++----------
 2 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 289d240..a582759 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -9191,6 +9191,8 @@ RequestXLogSwitch(void)
 
 	/* XLOG SWITCH has no data */
 	XLogBeginInsert();
+
+	XLogSetFlags(XLOG_NO_PROGRESS);
 	RecPtr = XLogInsert(RM_XLOG_ID, XLOG_SWITCH);
 
 	return RecPtr;
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index a729a3d..4b7ff4b 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -600,20 +600,38 @@ CheckArchiveTimeout(void)
 	/* Now we can do the real check */
 	if ((int) (now - last_xlog_switch_time) >= XLogArchiveTimeout)
 	{
-		XLogRecPtr	switchpoint;
-
-		/* OK, it's time to switch */
-		elog(LOG, "Request XLog Switch");
-		switchpoint = RequestXLogSwitch();
+		static XLogRecPtr last_xlog_switch_lsn = InvalidXLogRecPtr;
 
 		/*
-		 * If the returned pointer points exactly to a segment boundary,
-		 * assume nothing happened.
+		 * switch segment only when any substantial progress have made from
+		 * the last segment switching by timeout. Segment switching by other
+		 * reasons will cause last_xlog_switch_lsn stay behind but it doesn't
+		 * matter since it just causes possible one excessive segment switch.
 		 */
-		if ((switchpoint % XLogSegSize) != 0)
-			ereport(DEBUG1,
-				(errmsg("transaction log switch forced (archive_timeout=%d)",
-						XLogArchiveTimeout)));
+		if (GetProgressRecPtr() > last_xlog_switch_lsn)
+		{
+			XLogRecPtr	switchpoint;
+
+			/* OK, it's time to switch */
+			elog(LOG, "Request XLog Switch");
+			switchpoint = RequestXLogSwitch();
+
+			/*
+			 * If the returned pointer points exactly to a segment boundary,
+			 * assume nothing happened.
+			 */
+			if ((switchpoint % XLogSegSize) != 0)
+				ereport(DEBUG1,
+						(errmsg("transaction log switch forced (archive_timeout=%d)",
+								XLogArchiveTimeout)));
+
+			/*
+			 * This switchpoint is not the LSN for the next XLOG record but
+			 * just after this log switch record. But either will do for
+			 * comparing with GetProgressRecPtr().
+			 */
+			last_xlog_switch_lsn = switchpoint;
+		}
 
 		/*
 		 * Update state in any case, so we don't retry constantly when the
-- 
2.9.2

