aboutsummaryrefslogtreecommitdiff
path: root/src/backend/postmaster/walsummarizer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/postmaster/walsummarizer.c')
-rw-r--r--src/backend/postmaster/walsummarizer.c197
1 files changed, 143 insertions, 54 deletions
diff --git a/src/backend/postmaster/walsummarizer.c b/src/backend/postmaster/walsummarizer.c
index 55dc2ea8f53..83c178e7662 100644
--- a/src/backend/postmaster/walsummarizer.c
+++ b/src/backend/postmaster/walsummarizer.c
@@ -154,7 +154,8 @@ static void SummarizeSmgrRecord(XLogReaderState *xlogreader,
BlockRefTable *brtab);
static void SummarizeXactRecord(XLogReaderState *xlogreader,
BlockRefTable *brtab);
-static bool SummarizeXlogRecord(XLogReaderState *xlogreader);
+static bool SummarizeXlogRecord(XLogReaderState *xlogreader,
+ bool *new_fast_forward);
static int summarizer_read_local_xlog_page(XLogReaderState *state,
XLogRecPtr targetPagePtr,
int reqLen,
@@ -802,6 +803,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
char final_path[MAXPGPATH];
WalSummaryIO io;
BlockRefTable *brtab = CreateEmptyBlockRefTable();
+ bool fast_forward = true;
/* Initialize private data for xlogreader. */
private_data = (SummarizerReadLocalXLogPrivate *)
@@ -900,7 +902,7 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
int block_id;
char *errormsg;
XLogRecord *record;
- bool stop_requested = false;
+ uint8 rmid;
HandleWalSummarizerInterrupts();
@@ -969,56 +971,86 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
break;
}
- /* Special handling for particular types of WAL records. */
- switch (XLogRecGetRmid(xlogreader))
- {
- case RM_DBASE_ID:
- SummarizeDbaseRecord(xlogreader, brtab);
- break;
- case RM_SMGR_ID:
- SummarizeSmgrRecord(xlogreader, brtab);
- break;
- case RM_XACT_ID:
- SummarizeXactRecord(xlogreader, brtab);
- break;
- case RM_XLOG_ID:
- stop_requested = SummarizeXlogRecord(xlogreader);
- break;
- default:
- break;
- }
-
/*
- * If we've been told that it's time to end this WAL summary file, do
- * so. As an exception, if there's nothing included in this WAL
- * summary file yet, then stopping doesn't make any sense, and we
- * should wait until the next stop point instead.
+ * Certain types of records require special handling. Redo points and
+ * shutdown checkpoints trigger creation of new summary files and can
+ * also cause us to enter or exit "fast forward" mode. Other types of
+ * records can require special updates to the block reference table.
*/
- if (stop_requested && xlogreader->ReadRecPtr > summary_start_lsn)
+ rmid = XLogRecGetRmid(xlogreader);
+ if (rmid == RM_XLOG_ID)
{
- summary_end_lsn = xlogreader->ReadRecPtr;
- break;
+ bool new_fast_forward;
+
+ /*
+ * If we've already processed some WAL records when we hit a redo
+ * point or shutdown checkpoint, then we stop summarization before
+ * including this record in the current file, so that it will be
+ * the first record in the next file.
+ *
+ * When we hit one of those record types as the first record in a
+ * file, we adjust our notion of whether we're fast-forwarding.
+ * Any WAL generated with wal_level=minimal must be skipped
+ * without actually generating any summary file, because an
+ * incremental backup that crosses such WAL would be unsafe.
+ */
+ if (SummarizeXlogRecord(xlogreader, &new_fast_forward))
+ {
+ if (xlogreader->ReadRecPtr > summary_start_lsn)
+ {
+ summary_end_lsn = xlogreader->ReadRecPtr;
+ break;
+ }
+ else
+ fast_forward = new_fast_forward;
+ }
+ }
+ else if (!fast_forward)
+ {
+ /*
+ * This switch handles record types that require extra updates to
+ * the contents of the block reference table.
+ */
+ switch (rmid)
+ {
+ case RM_DBASE_ID:
+ SummarizeDbaseRecord(xlogreader, brtab);
+ break;
+ case RM_SMGR_ID:
+ SummarizeSmgrRecord(xlogreader, brtab);
+ break;
+ case RM_XACT_ID:
+ SummarizeXactRecord(xlogreader, brtab);
+ break;
+ }
}
- /* Feed block references from xlog record to block reference table. */
- for (block_id = 0; block_id <= XLogRecMaxBlockId(xlogreader);
- block_id++)
+ /*
+ * If we're in fast-forward mode, we don't really need to do anything.
+ * Otherwise, feed block references from xlog record to block
+ * reference table.
+ */
+ if (!fast_forward)
{
- RelFileLocator rlocator;
- ForkNumber forknum;
- BlockNumber blocknum;
+ for (block_id = 0; block_id <= XLogRecMaxBlockId(xlogreader);
+ block_id++)
+ {
+ RelFileLocator rlocator;
+ ForkNumber forknum;
+ BlockNumber blocknum;
- if (!XLogRecGetBlockTagExtended(xlogreader, block_id, &rlocator,
- &forknum, &blocknum, NULL))
- continue;
+ if (!XLogRecGetBlockTagExtended(xlogreader, block_id, &rlocator,
+ &forknum, &blocknum, NULL))
+ continue;
- /*
- * As we do elsewhere, ignore the FSM fork, because it's not fully
- * WAL-logged.
- */
- if (forknum != FSM_FORKNUM)
- BlockRefTableMarkBlockModified(brtab, &rlocator, forknum,
- blocknum);
+ /*
+ * As we do elsewhere, ignore the FSM fork, because it's not
+ * fully WAL-logged.
+ */
+ if (forknum != FSM_FORKNUM)
+ BlockRefTableMarkBlockModified(brtab, &rlocator, forknum,
+ blocknum);
+ }
}
/* Update our notion of where this summary file ends. */
@@ -1047,9 +1079,10 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
/*
* If a timeline switch occurs, we may fail to make any progress at all
* before exiting the loop above. If that happens, we don't write a WAL
- * summary file at all.
+ * summary file at all. We can also skip writing a file if we're in
+ * fast-forward mode.
*/
- if (summary_end_lsn > summary_start_lsn)
+ if (summary_end_lsn > summary_start_lsn && !fast_forward)
{
/* Generate temporary and final path name. */
snprintf(temp_path, MAXPGPATH,
@@ -1085,6 +1118,14 @@ SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact,
durable_rename(temp_path, final_path, ERROR);
}
+ /* If we skipped a non-zero amount of WAL, log a debug message. */
+ if (summary_end_lsn > summary_start_lsn && fast_forward)
+ ereport(DEBUG1,
+ errmsg("skipped summarizing WAL on TLI %u from %X/%X to %X/%X",
+ tli,
+ LSN_FORMAT_ARGS(summary_start_lsn),
+ LSN_FORMAT_ARGS(summary_end_lsn)));
+
return summary_end_lsn;
}
@@ -1263,22 +1304,70 @@ SummarizeXactRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
/*
* Special handling for WAL records with RM_XLOG_ID.
+ *
+ * The return value is true if WAL summarization should stop before this
+ * record and false otherwise. When the return value is true,
+ * *new_fast_forward indicates whether future processing should be done
+ * in fast forward mode (i.e. read WAL without emitting summaries) or not.
*/
static bool
-SummarizeXlogRecord(XLogReaderState *xlogreader)
+SummarizeXlogRecord(XLogReaderState *xlogreader, bool *new_fast_forward)
{
uint8 info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
+ int record_wal_level;
- if (info == XLOG_CHECKPOINT_REDO || info == XLOG_CHECKPOINT_SHUTDOWN)
+ if (info == XLOG_CHECKPOINT_REDO)
{
- /*
- * This is an LSN at which redo might begin, so we'd like
- * summarization to stop just before this WAL record.
- */
- return true;
+ /* Payload is wal_level at the time record was written. */
+ memcpy(&record_wal_level, XLogRecGetData(xlogreader), sizeof(int));
}
+ else if (info == XLOG_CHECKPOINT_SHUTDOWN)
+ {
+ CheckPoint rec_ckpt;
- return false;
+ /* Extract wal_level at time record was written from payload. */
+ memcpy(&rec_ckpt, XLogRecGetData(xlogreader), sizeof(CheckPoint));
+ record_wal_level = rec_ckpt.wal_level;
+ }
+ else if (info == XLOG_PARAMETER_CHANGE)
+ {
+ xl_parameter_change xlrec;
+
+ /* Extract wal_level at time record was written from payload. */
+ memcpy(&xlrec, XLogRecGetData(xlogreader),
+ sizeof(xl_parameter_change));
+ record_wal_level = xlrec.wal_level;
+ }
+ else if (info == XLOG_END_OF_RECOVERY)
+ {
+ xl_end_of_recovery xlrec;
+
+ /* Extract wal_level at time record was written from payload. */
+ memcpy(&xlrec, XLogRecGetData(xlogreader), sizeof(xl_end_of_recovery));
+ record_wal_level = xlrec.wal_level;
+ }
+ else
+ {
+ /* No special handling required. Return false. */
+ return false;
+ }
+
+ /*
+ * Redo can only begin at an XLOG_CHECKPOINT_REDO or
+ * XLOG_CHECKPOINT_SHUTDOWN record, so we want WAL summarization to begin
+ * at those points. Hence, when those records are encountered, return
+ * true, so that we stop just before summarizing either of those records.
+ *
+ * We also reach here if we just saw XLOG_END_OF_RECOVERY or
+ * XLOG_PARAMETER_CHANGE. These are not places where recovery can start,
+ * but they're still relevant here. A new timeline can begin with
+ * XLOG_END_OF_RECOVERY, so we need to confirm the WAL level at that
+ * point; and a restart can provoke XLOG_PARAMETER_CHANGE after an
+ * intervening change to postgresql.conf, which might force us to stop
+ * summarizing.
+ */
+ *new_fast_forward = (record_wal_level == WAL_LEVEL_MINIMAL);
+ return true;
}
/*