Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 402b586

Browse files
committed
Do not summarize WAL if generated with wal_level=minimal.
To do this, we must include the wal_level in the first WAL record covered by each summary file; so add wal_level to struct Checkpoint and the payload of XLOG_CHECKPOINT_REDO and XLOG_END_OF_RECOVERY. This, in turn, requires bumping XLOG_PAGE_MAGIC and, since the Checkpoint is also stored in the control file, also PG_CONTROL_VERSION. It's not great to do that so late in the release cycle, but the alternative seems to ship v17 without robust protections against this scenario, which could result in corrupted incremental backups. A side effect of this patch is that, when a server with wal_level=replica is started with summarize_wal=on for the first time, summarization will no longer begin with the oldest WAL that still exists in pg_wal, but rather from the first checkpoint after that. This change should be harmless, because a WAL summary for a partial checkpoint cycle can never make an incremental backup possible when it would otherwise not have been. Report by Fujii Masao. Patch by me. Review and/or testing by Jakub Wartak and Fujii Masao. Discussion: http://postgr.es/m/6e30082e-041b-4e31-9633-95a66de76f5d@oss.nttdata.com
1 parent a0a5869 commit 402b586

File tree

9 files changed

+278
-81
lines changed

9 files changed

+278
-81
lines changed

doc/src/sgml/config.sgml

+11-5
Original file line numberDiff line numberDiff line change
@@ -4318,11 +4318,17 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
43184318
<listitem>
43194319
<para>
43204320
Enables the WAL summarizer process. Note that WAL summarization can
4321-
be enabled either on a primary or on a standby. WAL summarization
4322-
cannot be enabled when <varname>wal_level</varname> is set to
4323-
<literal>minimal</literal>. This parameter can only be set in the
4324-
<filename>postgresql.conf</filename> file or on the server command line.
4325-
The default is <literal>off</literal>.
4321+
be enabled either on a primary or on a standby. This parameter can only
4322+
be set in the <filename>postgresql.conf</filename> file or on the server
4323+
command line. The default is <literal>off</literal>.
4324+
</para>
4325+
<para>
4326+
The server cannot be started with <literal>summarize_wal=on</literal>
4327+
if <literal>wal_level</literal> is set to <literal>minimal</literal>. If
4328+
<literal>summarize_wal=on</literal> is configured after server startup
4329+
while <literal>wal_level=minimal</literal>, the summarizer will run
4330+
but refuse to generate summary files for any WAL generated with
4331+
<literal>wal_level=minimal</literal>.
43264332
</para>
43274333
</listitem>
43284334
</varlistentry>

doc/src/sgml/func.sgml

+11
Original file line numberDiff line numberDiff line change
@@ -28001,6 +28001,17 @@ acl | {postgres=arwdDxtm/postgres,foo=r/postgres}
2800128001
not running, it will be equal to <literal>summarized_lsn</literal>.
2800228002
<literal>summarizer_pid</literal> is the PID of the WAL summarizer
2800328003
process, if it is running, and otherwise NULL.
28004+
</para>
28005+
<para>
28006+
As a special exception, the WAL summarizer will refuse to generate
28007+
WAL summary files if run on WAL generated under
28008+
<literal>wal_level=minimal</literal>, since such summaries would be
28009+
unsafe to use as the basis for an incremental backup. In this case,
28010+
the fields above will continue to advance as if summaries were being
28011+
generated, but nothing will be written to disk. Once the summarizer
28012+
reaches WAL generated while <literal>wal_level</literal> was set
28013+
to <literal>replica</literal> or higher, it will resume writing
28014+
summaries to disk.
2800428015
</para></entry>
2800528016
</row>
2800628017
</tbody>

src/backend/access/rmgrdesc/xlogdesc.c

+31-16
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,27 @@ const struct config_enum_entry wal_level_options[] = {
3333
{NULL, 0, false}
3434
};
3535

36+
/*
37+
* Find a string representation for wal_level
38+
*/
39+
static const char *
40+
get_wal_level_string(int wal_level)
41+
{
42+
const struct config_enum_entry *entry;
43+
const char *wal_level_str = "?";
44+
45+
for (entry = wal_level_options; entry->name; entry++)
46+
{
47+
if (entry->val == wal_level)
48+
{
49+
wal_level_str = entry->name;
50+
break;
51+
}
52+
}
53+
54+
return wal_level_str;
55+
}
56+
3657
void
3758
xlog_desc(StringInfo buf, XLogReaderState *record)
3859
{
@@ -45,14 +66,15 @@ xlog_desc(StringInfo buf, XLogReaderState *record)
4566
CheckPoint *checkpoint = (CheckPoint *) rec;
4667

4768
appendStringInfo(buf, "redo %X/%X; "
48-
"tli %u; prev tli %u; fpw %s; xid %u:%u; oid %u; multi %u; offset %u; "
69+
"tli %u; prev tli %u; fpw %s; wal_level %s; xid %u:%u; oid %u; multi %u; offset %u; "
4970
"oldest xid %u in DB %u; oldest multi %u in DB %u; "
5071
"oldest/newest commit timestamp xid: %u/%u; "
5172
"oldest running xid %u; %s",
5273
LSN_FORMAT_ARGS(checkpoint->redo),
5374
checkpoint->ThisTimeLineID,
5475
checkpoint->PrevTimeLineID,
5576
checkpoint->fullPageWrites ? "true" : "false",
77+
get_wal_level_string(checkpoint->wal_level),
5678
EpochFromFullTransactionId(checkpoint->nextXid),
5779
XidFromFullTransactionId(checkpoint->nextXid),
5880
checkpoint->nextOid,
@@ -95,20 +117,9 @@ xlog_desc(StringInfo buf, XLogReaderState *record)
95117
{
96118
xl_parameter_change xlrec;
97119
const char *wal_level_str;
98-
const struct config_enum_entry *entry;
99120

100121
memcpy(&xlrec, rec, sizeof(xl_parameter_change));
101-
102-
/* Find a string representation for wal_level */
103-
wal_level_str = "?";
104-
for (entry = wal_level_options; entry->name; entry++)
105-
{
106-
if (entry->val == xlrec.wal_level)
107-
{
108-
wal_level_str = entry->name;
109-
break;
110-
}
111-
}
122+
wal_level_str = get_wal_level_string(xlrec.wal_level);
112123

113124
appendStringInfo(buf, "max_connections=%d max_worker_processes=%d "
114125
"max_wal_senders=%d max_prepared_xacts=%d "
@@ -135,9 +146,10 @@ xlog_desc(StringInfo buf, XLogReaderState *record)
135146
xl_end_of_recovery xlrec;
136147

137148
memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
138-
appendStringInfo(buf, "tli %u; prev tli %u; time %s",
149+
appendStringInfo(buf, "tli %u; prev tli %u; time %s; wal_level %s",
139150
xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
140-
timestamptz_to_str(xlrec.end_time));
151+
timestamptz_to_str(xlrec.end_time),
152+
get_wal_level_string(xlrec.wal_level));
141153
}
142154
else if (info == XLOG_OVERWRITE_CONTRECORD)
143155
{
@@ -150,7 +162,10 @@ xlog_desc(StringInfo buf, XLogReaderState *record)
150162
}
151163
else if (info == XLOG_CHECKPOINT_REDO)
152164
{
153-
/* No details to write out */
165+
int wal_level;
166+
167+
memcpy(&wal_level, rec, sizeof(int));
168+
appendStringInfo(buf, "wal_level %s", get_wal_level_string(wal_level));
154169
}
155170
}
156171

src/backend/access/transam/xlog.c

+4-4
Original file line numberDiff line numberDiff line change
@@ -6934,6 +6934,7 @@ CreateCheckPoint(int flags)
69346934
WALInsertLockAcquireExclusive();
69356935

69366936
checkPoint.fullPageWrites = Insert->fullPageWrites;
6937+
checkPoint.wal_level = wal_level;
69376938

69386939
if (shutdown)
69396940
{
@@ -6987,11 +6988,9 @@ CreateCheckPoint(int flags)
69876988
*/
69886989
if (!shutdown)
69896990
{
6990-
int dummy = 0;
6991-
6992-
/* Record must have payload to avoid assertion failure. */
6991+
/* Include WAL level in record for WAL summarizer's benefit. */
69936992
XLogBeginInsert();
6994-
XLogRegisterData((char *) &dummy, sizeof(dummy));
6993+
XLogRegisterData((char *) &wal_level, sizeof(wal_level));
69956994
(void) XLogInsert(RM_XLOG_ID, XLOG_CHECKPOINT_REDO);
69966995

69976996
/*
@@ -7314,6 +7313,7 @@ CreateEndOfRecoveryRecord(void)
73147313
elog(ERROR, "can only be used to end recovery");
73157314

73167315
xlrec.end_time = GetCurrentTimestamp();
7316+
xlrec.wal_level = wal_level;
73177317

73187318
WALInsertLockAcquireExclusive();
73197319
xlrec.ThisTimeLineID = XLogCtl->InsertTimeLineID;

0 commit comments

Comments
 (0)