Re: [BUG] Checkpointer on hot standby runs without looking checkpoint_segments - Mailing list pgsql-hackers
From | Kyotaro HORIGUCHI |
---|---|
Subject | Re: [BUG] Checkpointer on hot standby runs without looking checkpoint_segments |
Date | |
Msg-id | 20120419.142007.249982022.horiguchi.kyotaro@lab.ntt.co.jp Whole thread Raw |
In response to | Re: [BUG] Checkpointer on hot standby runs without looking checkpoint_segments (Kyotaro HORIGUCHI <horiguchi.kyotaro@lab.ntt.co.jp>) |
Responses |
Re: [BUG] Checkpointer on hot standby runs without looking checkpoint_segments
|
List | pgsql-hackers |
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: unconditionallynot allowed to insert XLOG @@ -206,7 +212,6 @@ static TimestampTz recoveryTargetTime;static char *recoveryTargetName;/* options taken from recovery.conffor 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 forWAL to arrive or failover trigger file * to appear. @@ -619,6 +629,7 @@ static void SetLatestXTime(TimestampTz xtime);static void SetCurrentChunkStartTime(TimestampTz xtime);staticvoid 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'vereached 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("recoverycommand 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"))); elseif (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 restartpointif 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);externbool HotStandbyActive(void); +extern bool IsStandbyMode(void);extern bool XLogInsertAllowed(void);extern void GetXLogReceiptTime(TimestampTz *rtime, bool*fromStream);extern XLogRecPtr GetXLogReplayRecPtr(XLogRecPtr *restoreLastRecPtr);
pgsql-hackers by date: