A restartpoint is triggered when a checkpoint record is reached if at
least <varname>checkpoint_timeout</> seconds have passed since the last
restartpoint, or if WAL size is about to exceed
- <varname>max_wal_size</>.
+ <varname>max_wal_size</>. However, because of limitations on when a
+ restartpoint can be performed, <varname>max_wal_size</> is often exceeded
+ during recovery, by up to one checkpoint cycle's worth of WAL.
+ (<varname>max_wal_size</> is never a hard limit anyway, so you should
+ always leave plenty of headroom to avoid running out of disk space.)
</para>
<para>
/*
* Initialize checkpointer-private variables used during
- * checkpoint
+ * checkpoint.
*/
ckpt_active = true;
- if (!do_restartpoint)
+ if (do_restartpoint)
+ ckpt_start_recptr = GetXLogReplayRecPtr(NULL);
+ else
ckpt_start_recptr = GetInsertRecPtr();
ckpt_start_time = now;
ckpt_cached_elapsed = 0;
/*
* IsCheckpointOnSchedule -- are we on schedule to finish this checkpoint
- * in time?
+ * (or restartpoint) in time?
*
* Compares the current progress against the time/segments elapsed since last
* checkpoint, and returns true if the progress we've made this far is greater
* compares against RedoRecptr, so this is not completely accurate.
* However, it's good enough for our purposes, we're only calculating an
* estimate anyway.
+ *
+ * During recovery, we compare last replayed WAL record's location with
+ * the location computed before calling CreateRestartPoint. That maintains
+ * the same pacing as we have during checkpoints in normal operation, but
+ * we might exceed max_wal_size by a fair amount. That's because there can
+ * be a large gap between a checkpoint's redo-pointer and the checkpoint
+ * record itself, and we only start the restartpoint after we've seen the
+ * checkpoint record. (The gap is typically up to CheckPointSegments *
+ * checkpoint_completion_target where checkpoint_completion_target is the
+ * value that was in effect when the WAL was generated).
*/
- if (!RecoveryInProgress())
- {
+ if (RecoveryInProgress())
+ recptr = GetXLogReplayRecPtr(NULL);
+ else
recptr = GetInsertRecPtr();
- elapsed_xlogs = (((double) (recptr - ckpt_start_recptr)) / XLogSegSize) / CheckPointSegments;
+ elapsed_xlogs = (((double) (recptr - ckpt_start_recptr)) / XLogSegSize) / CheckPointSegments;
- if (progress < elapsed_xlogs)
- {
- ckpt_cached_elapsed = elapsed_xlogs;
- return false;
- }
+ if (progress < elapsed_xlogs)
+ {
+ ckpt_cached_elapsed = elapsed_xlogs;
+ return false;
}
/*