* here. It's used by the background writer when it wants to create
* a restartpoint.
*
- * is info_lck spinlock a bit too light-weight to protect these?
+ * Protected by info_lck. XXX Is a spinlock too light-weight for these?
*/
XLogRecPtr lastCheckPointRecPtr;
CheckPoint lastCheckPoint;
minRecoveryPoint.xlogid, minRecoveryPoint.xrecoff)));
/*
- * Let postmaster know we've started redo now.
+ * Let postmaster know we've started redo now, so that it can
+ * launch bgwriter. We don't bother during crash recovery; we can
+ * only perform restartpoints during archive recovery anyway. And
+ * we'd like to keep crash recovery simple, to avoid introducing
+ * bugs into that codepath that could stop you from recovering.
*
* After this point, we can no longer assume that there's no other
* processes running concurrently.
#endif
/*
- * Process any requests or signals received recently.
+ * Check if we were requested to exit without finishing
+ * recovery.
*/
if (shutdown_requested)
{
- /*
- * We were requested to exit without finishing recovery.
- */
UpdateMinRecoveryPoint(ReadRecPtr);
proc_exit(0);
}
* This is similar to CreateCheckPoint, but is used during WAL recovery
* to establish a point from which recovery can roll forward without
* replaying the entire recovery log.
+ *
+ * Returns true if a new restartpoint was established. We can only establish
+ * a restartpoint if we have replayed a checkpoint record since last
+ * restartpoint.
*/
-void
+bool
CreateRestartPoint(int flags)
{
XLogRecPtr lastCheckPointRecPtr;
(errmsg("skipping restartpoint, already performed at %X/%X",
lastCheckPoint.redo.xlogid, lastCheckPoint.redo.xrecoff)));
LWLockRelease(CheckpointLock);
- return;
+ return false;
}
/*
ereport(DEBUG2,
(errmsg("skipping restartpoint, recovery has already ended")));
LWLockRelease(CheckpointLock);
- return;
+ return false;
}
if (log_checkpoints)
timestamptz_to_str(recoveryLastXTime))));
LWLockRelease(CheckpointLock);
+ return true;
}
/*
*/
if (do_checkpoint)
{
+ bool ckpt_performed = false;
+
/* use volatile pointer to prevent code rearrangement */
volatile BgWriterShmemStruct *bgs = BgWriterShmem;
* Do the checkpoint.
*/
if (!BgWriterRecoveryMode)
+ {
CreateCheckPoint(flags);
+ ckpt_performed = true;
+ }
else
- CreateRestartPoint(flags);
+ ckpt_performed = CreateRestartPoint(flags);
/*
* After any checkpoint, close all smgr files. This is so we
/*
* Indicate checkpoint completion to any waiting backends.
*/
- SpinLockAcquire(&bgs->ckpt_lck);
- bgs->ckpt_done = bgs->ckpt_started;
- SpinLockRelease(&bgs->ckpt_lck);
+ if (ckpt_performed)
+ {
+ SpinLockAcquire(&bgs->ckpt_lck);
+ bgs->ckpt_done = bgs->ckpt_started;
+ SpinLockRelease(&bgs->ckpt_lck);
+
+ /*
+ * Note we record the checkpoint start time not end time as
+ * last_checkpoint_time. This is so that time-driven
+ * checkpoints happen at a predictable spacing.
+ */
+ last_checkpoint_time = now;
+ }
+ else
+ {
+ /*
+ * We were not able to perform the restartpoint (checkpoints
+ * throw an ERROR in case of error). Most likely because we
+ * have not received a new checkpoint WAL record since the
+ * last restartpoint. Try again in 15 s.
+ */
+ last_checkpoint_time = now - CheckPointTimeout - 15;
+ }
ckpt_active = false;
-
- /*
- * Note we record the checkpoint start time not end time as
- * last_checkpoint_time. This is so that time-driven checkpoints
- * happen at a predictable spacing.
- */
- last_checkpoint_time = now;
}
else
BgBufferSync();
extern void ShutdownXLOG(int code, Datum arg);
extern void InitXLOGAccess(void);
extern void CreateCheckPoint(int flags);
-extern void CreateRestartPoint(int flags);
+extern bool CreateRestartPoint(int flags);
extern void XLogPutNextOid(Oid nextOid);
extern XLogRecPtr GetRedoRecPtr(void);
extern XLogRecPtr GetInsertRecPtr(void);