Hello, this is new version of standby checkpoint_segments patch.

 - xlog.c: Make StandbyMode shared.

 - checkpointer.c: Use IsStandbyMode() to check if postmaster is 
   under standby mode.

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center

== My e-mail address has been changed since Apr. 1, 2012.

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 8d0aabf..2457840 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -177,6 +177,12 @@ static bool LocalRecoveryInProgress = true;
 static bool LocalHotStandbyActive = false;
 
 /*
+ * Local copy of SharedIsStandbyMode variable.  True actually means "not known,
+ * need to check the shared state".
+ */
+static bool LocalIsStandbyMode = true;
+
+/*
  * Local state for XLogInsertAllowed():
  *		1: unconditionally allowed to insert XLOG
  *		0: unconditionally not allowed to insert XLOG
@@ -206,7 +212,6 @@ static TimestampTz recoveryTargetTime;
 static char *recoveryTargetName;
 
 /* options taken from recovery.conf for XLOG streaming */
-static bool StandbyMode = false;
 static char *PrimaryConnInfo = NULL;
 static char *TriggerFile = NULL;
 
@@ -427,6 +432,11 @@ typedef struct XLogCtlData
 	bool		SharedHotStandbyActive;
 
 	/*
+	 * SharedInStandbyMode indicates if we are running in standby mode.
+	 */
+	bool		SharedIsStandbyMode;
+
+	/*
 	 * recoveryWakeupLatch is used to wake up the startup process to continue
 	 * WAL replay, if it is waiting for WAL to arrive or failover trigger file
 	 * to appear.
@@ -619,6 +629,7 @@ static void SetLatestXTime(TimestampTz xtime);
 static void SetCurrentChunkStartTime(TimestampTz xtime);
 static void CheckRequiredParameterValues(void);
 static void XLogReportParameters(void);
+static void ExitStandbyMode(void);
 static void LocalSetXLogInsertAllowed(void);
 static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
 static void KeepLogSeg(XLogRecPtr recptr, uint32 *logId, uint32 *logSeg);
@@ -3115,7 +3126,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 				 * incorrectly conclude we've reached the end of WAL and we're
 				 * done recovering ...
 				 */
-				if (StandbyMode && stat_buf.st_size < expectedSize)
+				if (IsStandbyMode() && stat_buf.st_size < expectedSize)
 					elevel = DEBUG1;
 				else
 					elevel = FATAL;
@@ -4072,7 +4083,7 @@ next_record_is_invalid:
 	}
 
 	/* In standby-mode, keep trying */
-	if (StandbyMode)
+	if (IsStandbyMode())
 		goto retry;
 	else
 		return NULL;
@@ -5098,6 +5109,7 @@ XLOGShmemInit(void)
 	XLogCtl->XLogCacheBlck = XLOGbuffers - 1;
 	XLogCtl->SharedRecoveryInProgress = true;
 	XLogCtl->SharedHotStandbyActive = false;
+	XLogCtl->SharedIsStandbyMode = true;
 	XLogCtl->Insert.currpage = (XLogPageHeader) (XLogCtl->pages);
 	SpinLockInit(&XLogCtl->info_lck);
 	InitSharedLatch(&XLogCtl->recoveryWakeupLatch);
@@ -5289,6 +5301,7 @@ readRecoveryCommandFile(void)
 	FILE	   *fd;
 	TimeLineID	rtli = 0;
 	bool		rtliGiven = false;
+	bool        standby_mode = false;
 	ConfigVariable *item,
 			   *head = NULL,
 			   *tail = NULL;
@@ -5439,13 +5452,14 @@ readRecoveryCommandFile(void)
 		}
 		else if (strcmp(item->name, "standby_mode") == 0)
 		{
-			if (!parse_bool(item->value, &StandbyMode))
+			if (!parse_bool(item->value, &standby_mode))
 				ereport(ERROR,
 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 						 errmsg("parameter \"%s\" requires a Boolean value",
 								"standby_mode")));
 			ereport(DEBUG2,
 					(errmsg_internal("standby_mode = '%s'", item->value)));
+
 		}
 		else if (strcmp(item->name, "primary_conninfo") == 0)
 		{
@@ -5470,7 +5484,7 @@ readRecoveryCommandFile(void)
 	/*
 	 * Check for compulsory parameters
 	 */
-	if (StandbyMode)
+	if (standby_mode)
 	{
 		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
 			ereport(WARNING,
@@ -5480,6 +5494,7 @@ readRecoveryCommandFile(void)
 	}
 	else
 	{
+		ExitStandbyMode();
 		if (recoveryRestoreCommand == NULL)
 			ereport(FATAL,
 					(errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
@@ -6086,7 +6101,7 @@ StartupXLOG(void)
 
 	if (InArchiveRecovery)
 	{
-		if (StandbyMode)
+		if (IsStandbyMode())
 			ereport(LOG,
 					(errmsg("entering standby mode")));
 		else if (recoveryTarget == RECOVERY_TARGET_XID)
@@ -6110,7 +6125,7 @@ StartupXLOG(void)
 	 * Take ownership of the wakeup latch if we're going to sleep during
 	 * recovery.
 	 */
-	if (StandbyMode)
+	if (IsStandbyMode())
 		OwnLatch(&XLogCtl->recoveryWakeupLatch);
 
 	if (read_backup_label(&checkPointLoc, &backupEndRequired,
@@ -6169,7 +6184,7 @@ StartupXLOG(void)
 					(errmsg("checkpoint record is at %X/%X",
 							checkPointLoc.xlogid, checkPointLoc.xrecoff)));
 		}
-		else if (StandbyMode)
+		else if (IsStandbyMode())
 		{
 			/*
 			 * The last valid checkpoint record required for a streaming
@@ -6683,7 +6698,7 @@ StartupXLOG(void)
 	 * We don't need the latch anymore. It's not strictly necessary to disown
 	 * it, but let's do it for the sake of tidiness.
 	 */
-	if (StandbyMode)
+	if (IsStandbyMode())
 		DisownLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/*
@@ -6691,7 +6706,7 @@ StartupXLOG(void)
 	 * recovery to force fetching the files (which would be required at end of
 	 * recovery, e.g., timeline history file) from archive or pg_xlog.
 	 */
-	StandbyMode = false;
+	ExitStandbyMode();
 
 	/*
 	 * Re-fetch the last valid or last applied record, so we can identify the
@@ -7096,7 +7111,7 @@ RecoveryInProgress(void)
  * since normal backends won't ever be able to connect until this returns
  * true. Postmaster knows this by way of signal, not via shared memory.
  *
- * Unlike testing standbyState, this works in any process that's connected to
+ * Unlike testing InRecovery, this works in any process that's connected to
  * shared memory.
  */
 bool
@@ -7124,6 +7139,53 @@ HotStandbyActive(void)
 }
 
 /*
+ * Are we running in standby mode?
+ *
+ * Unlike testing InRecovery, this works in any process that's connected to
+ * shared memory.
+ */
+bool
+IsStandbyMode(void)
+{
+	/*
+	 * We check shared state each time only until exiting standby mode. We
+	 * can't re-enter standby mode, so there's no need to keep checking after
+	 * the shared variable has once been seen false.
+	 */
+	if (!LocalIsStandbyMode)
+		return false;
+	else
+	{
+		/* use volatile pointer to prevent code rearrangement */
+		volatile XLogCtlData *xlogctl = XLogCtl;
+		
+		/* spinlock is essential on machines with weak memory ordering! */
+		SpinLockAcquire(&xlogctl->info_lck);
+		LocalIsStandbyMode = xlogctl->SharedIsStandbyMode;
+		SpinLockRelease(&xlogctl->info_lck);
+
+		return LocalIsStandbyMode;
+	}
+
+}
+
+
+/*
+ * Inform the processes connected to shared memory that we exit standby mode.
+ */
+static void
+ExitStandbyMode()
+{
+	/* use volatile pointer to prevent code rearrangement */
+	volatile XLogCtlData *xlogctl = XLogCtl;
+
+	/* spinlock is essential on machines with weak memory ordering! */
+	SpinLockAcquire(&xlogctl->info_lck);
+	LocalIsStandbyMode = xlogctl->SharedIsStandbyMode = false;
+	SpinLockRelease(&xlogctl->info_lck);
+}
+
+/*
  * Is this process allowed to insert new WAL records?
  *
  * Ordinarily this is essentially equivalent to !RecoveryInProgress().
@@ -10026,7 +10088,7 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
 		 * Request a restartpoint if we've replayed too much
 		 * xlog since the last one.
 		 */
-		if (StandbyMode && bgwriterLaunched)
+		if (IsStandbyMode() && bgwriterLaunched)
 		{
 			if (XLogCheckpointNeeded(readId, readSeg))
 			{
@@ -10048,7 +10110,7 @@ retry:
 	if (readFile < 0 ||
 		(readSource == XLOG_FROM_STREAM && !XLByteLT(*RecPtr, receivedUpto)))
 	{
-		if (StandbyMode)
+		if (IsStandbyMode())
 		{
 			/*
 			 * In standby mode, wait for the requested record to become
@@ -10362,7 +10424,7 @@ next_record_is_invalid:
 	readSource = 0;
 
 	/* In standby-mode, keep trying */
-	if (StandbyMode)
+	if (IsStandbyMode())
 		goto retry;
 	else
 		return false;
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index c9473f7..f91bd52 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -491,8 +491,8 @@ CheckpointerMain(void)
 			 * Initialize checkpointer-private variables used during checkpoint.
 			 */
 			ckpt_active = true;
-			if (!do_restartpoint)
-				ckpt_start_recptr = GetInsertRecPtr();
+			ckpt_start_recptr =
+				do_restartpoint ? GetXLogReplayRecPtr(NULL) : GetInsertRecPtr();
 			ckpt_start_time = now;
 			ckpt_cached_elapsed = 0;
 
@@ -715,6 +715,7 @@ IsCheckpointOnSchedule(double progress)
 	struct timeval now;
 	double		elapsed_xlogs,
 				elapsed_time;
+	bool        recovery_in_progress;
 
 	Assert(ckpt_active);
 
@@ -731,18 +732,27 @@ IsCheckpointOnSchedule(double progress)
 		return false;
 
 	/*
-	 * Check progress against WAL segments written and checkpoint_segments.
+	 * Check progress against WAL segments written, or replayed for
+	 * hot standby, and checkpoint_segments.
 	 *
 	 * We compare the current WAL insert location against the location
-	 * computed before calling CreateCheckPoint. The code in XLogInsert that
-	 * actually triggers a checkpoint when checkpoint_segments is exceeded
-	 * compares against RedoRecptr, so this is not completely accurate.
-	 * However, it's good enough for our purposes, we're only calculating an
-	 * estimate anyway.
+	 * computed before calling CreateCheckPoint. The code in
+	 * XLogInsert that actually triggers a checkpoint when
+	 * checkpoint_segments is exceeded compares against RedoRecPtr.
+	 * Similarly, we consult WAL replay location instead on hot
+	 * standbys and XLogPageRead compares it aganst RedoRecPtr, too.
+	 * Altough these are not completely accurate, it's good enough for
+	 * our purposes, we're only calculating an estimate anyway.
+	 */
+
+	/*
+	 * Inhibit governing progress by segments in archive recovery.
 	 */
-	if (!RecoveryInProgress())
+	recovery_in_progress = RecoveryInProgress();
+	if (!recovery_in_progress || IsStandbyMode())
 	{
-		recptr = GetInsertRecPtr();
+		recptr = recovery_in_progress ? GetXLogReplayRecPtr(NULL) :
+			GetInsertRecPtr();
 		elapsed_xlogs =
 			(((double) (int32) (recptr.xlogid - ckpt_start_recptr.xlogid)) * XLogSegsPerFile +
 			 ((double) recptr.xrecoff - (double) ckpt_start_recptr.xrecoff) / XLogSegSize) /
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index f8aecef..329119b 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -285,6 +285,7 @@ extern void issue_xlog_fsync(int fd, uint32 log, uint32 seg);
 
 extern bool RecoveryInProgress(void);
 extern bool HotStandbyActive(void);
+extern bool IsStandbyMode(void);
 extern bool XLogInsertAllowed(void);
 extern void GetXLogReceiptTime(TimestampTz *rtime, bool *fromStream);
 extern XLogRecPtr GetXLogReplayRecPtr(XLogRecPtr *restoreLastRecPtr);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to