Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitde76884

Browse files
committed
At promotion, archive last segment from old timeline with .partial suffix.
Previously, we would archive the possible-incomplete WAL segment with itsnormal filename, but that causes trouble if the server owning that timelineis still running, and tries to archive the same segment later. It's not nicefor the standby to trip up the master's archival like that. And it's prettyconfusing, anyway, to have an incomplete segment in the archive that'sindistinguishable from a normal, complete segment.To avoid such confusion, add a .partial suffix to the file. Or to be moreprecise, make a copy of the old segment under the .partial suffix, andarchive that instead of the original file. pg_receivexlog also uses the.partial suffix for the same purpose, to tell apart incompletely streamedfiles from complete ones.There is no automatic mechanism to use the .partial files at recovery, sothey will go unused, unless the administrator manually copies to them tothe pg_xlog directory (and removes the .partial suffix). Recovery won'tnormally need the WAL - when recovering to the new timeline, it will findthe same WAL on the first segment on the new timeline instead - but itnevertheless feels better to archive the file with the .partial suffix, fordebugging purposes if nothing else.
1 parent179cdd0 commitde76884

File tree

3 files changed

+107
-33
lines changed

3 files changed

+107
-33
lines changed

‎src/backend/access/transam/xlog.c

Lines changed: 101 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3020,24 +3020,22 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
30203020
}
30213021

30223022
/*
3023-
*Create anew XLOG filesegment by copying a pre-existing one.
3023+
*Copy aWAL segment filein pg_xlog directory.
30243024
*
3025-
* destsegno: identify segment to be created.
3025+
* dstfnamedestination filename
3026+
* srcfnamesource filename
3027+
* uptohow much of the source file to copy? (the rest is filled with
3028+
*zeros)
30263029
*
3027-
*srcTLI, srclog, srcseg: identify segment to be copied (could be from
3028-
*a different timeline)
3030+
*If dstfname is not given, the file is created with a temporary filename,
3031+
* which is returned. Both filenames are relative to the pg_xlog directory.
30293032
*
3030-
* upto: how much of the source file to copy? (the rest is filled with zeros)
3031-
*
3032-
* Currently this is only used during recovery, and so there are no locking
3033-
* considerations. But we should be just as tense as XLogFileInit to avoid
3034-
* emplacing a bogus file.
3033+
* NB: Any existing file with the same name will be overwritten!
30353034
*/
3036-
staticvoid
3037-
XLogFileCopy(XLogSegNodestsegno,TimeLineIDsrcTLI,XLogSegNosrcsegno,
3038-
intupto)
3035+
staticchar*
3036+
XLogFileCopy(char*dstfname,char*srcfname,intupto)
30393037
{
3040-
charpath[MAXPGPATH];
3038+
charsrcpath[MAXPGPATH];
30413039
chartmppath[MAXPGPATH];
30423040
charbuffer[XLOG_BLCKSZ];
30433041
intsrcfd;
@@ -3047,12 +3045,12 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
30473045
/*
30483046
* Open the source file
30493047
*/
3050-
XLogFilePath(path,srcTLI,srcsegno);
3051-
srcfd=OpenTransientFile(path,O_RDONLY |PG_BINARY,0);
3048+
snprintf(srcpath,MAXPGPATH,XLOGDIR"/%s",srcfname);
3049+
srcfd=OpenTransientFile(srcpath,O_RDONLY |PG_BINARY,0);
30523050
if (srcfd<0)
30533051
ereport(ERROR,
30543052
(errcode_for_file_access(),
3055-
errmsg("could not open file \"%s\": %m",path)));
3053+
errmsg("could not open file \"%s\": %m",srcpath)));
30563054

30573055
/*
30583056
* Copy into a temp file name.
@@ -3094,10 +3092,12 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
30943092
if (errno!=0)
30953093
ereport(ERROR,
30963094
(errcode_for_file_access(),
3097-
errmsg("could not read file \"%s\": %m",path)));
3095+
errmsg("could not read file \"%s\": %m",
3096+
srcpath)));
30983097
else
30993098
ereport(ERROR,
3100-
(errmsg("not enough data in file \"%s\"",path)));
3099+
(errmsg("not enough data in file \"%s\"",
3100+
srcpath)));
31013101
}
31023102
}
31033103
errno=0;
@@ -3131,10 +3131,24 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
31313131
CloseTransientFile(srcfd);
31323132

31333133
/*
3134-
* Now move the segment into place with its final name.
3134+
* Now move the segment into place with its final name. (Or just return
3135+
* the path to the file we created, if the caller wants to handle the
3136+
* rest on its own.)
31353137
*/
3136-
if (!InstallXLogFileSegment(&destsegno,tmppath, false,0, false))
3137-
elog(ERROR,"InstallXLogFileSegment should not have failed");
3138+
if (dstfname)
3139+
{
3140+
chardstpath[MAXPGPATH];
3141+
3142+
snprintf(dstpath,MAXPGPATH,XLOGDIR"/%s",dstfname);
3143+
if (rename(tmppath,dstpath)<0)
3144+
ereport(ERROR,
3145+
(errcode_for_file_access(),
3146+
errmsg("could not rename file \"%s\" to \"%s\": %m",
3147+
tmppath,dstpath)));
3148+
returnNULL;
3149+
}
3150+
else
3151+
returnpstrdup(tmppath);
31383152
}
31393153

31403154
/*
@@ -3577,7 +3591,8 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
35773591
while ((xlde=ReadDir(xldir,XLOGDIR))!=NULL)
35783592
{
35793593
/* Ignore files that are not XLOG segments */
3580-
if (!IsXLogFileName(xlde->d_name))
3594+
if (!IsXLogFileName(xlde->d_name)&&
3595+
!IsPartialXLogFileName(xlde->d_name))
35813596
continue;
35823597

35833598
/*
@@ -5189,25 +5204,79 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
51895204
* of the old timeline up to the switch point, to the starting WAL segment
51905205
* on the new timeline.
51915206
*
5192-
* Notify the archiver that the last WAL segment of the old timeline is
5193-
* ready to copy to archival storage if its .done file doesn't exist
5194-
* (e.g., if it's the restored WAL file, it's expected to have .done file).
5195-
* Otherwise, it is not archived for a while.
5207+
* What to do with the partial segment on the old timeline? If we don't
5208+
* archive it, and the server that created the WAL never archives it
5209+
* either (e.g. because it was hit by a meteor), it will never make it to
5210+
* the archive. That's OK from our point of view, because the new segment
5211+
* that we created with the new TLI contains all the WAL from the old
5212+
* timeline up to the switch point. But if you later try to do PITR to the
5213+
* "missing" WAL on the old timeline, recovery won't find it in the
5214+
* archive. It's physically present in the new file with new TLI, but
5215+
* recovery won't look there when it's recovering to the older timeline.
5216+
* On the other hand, if we archive the partial segment, and the original
5217+
* server on that timeline is still running and archives the completed
5218+
* version of the same segment later, it will fail. (We used to do that in
5219+
* 9.4 and below, and it caused such problems).
5220+
*
5221+
* As a compromise, we archive the last segment with the .partial suffix.
5222+
* Archive recovery will never try to read .partial segments, so they will
5223+
* normally go unused. But in the odd PITR case, the administrator can
5224+
* copy them manually to the pg_xlog directory (removing the suffix). They
5225+
* can be useful in debugging, too.
5226+
*
5227+
* If a .done file already exists for the old timeline, however, there is
5228+
* already a complete copy of the file in the archive, and there is no
5229+
* need to archive the partial one. (In particular, if it was restored
5230+
* from the archive to begin with, it's expected to have .done file).
51965231
*/
51975232
if (endLogSegNo==startLogSegNo)
51985233
{
5199-
XLogFileCopy(startLogSegNo,endTLI,endLogSegNo,
5200-
endOfLog %XLOG_SEG_SIZE);
5234+
char*tmpfname;
5235+
5236+
XLogFileName(xlogfname,endTLI,endLogSegNo);
5237+
5238+
/*
5239+
* Make a copy of the file on the new timeline.
5240+
*
5241+
* Writing WAL isn't allowed yet, so there are no locking
5242+
* considerations. But we should be just as tense as XLogFileInit to
5243+
* avoid emplacing a bogus file.
5244+
*/
5245+
tmpfname=XLogFileCopy(NULL,xlogfname,endOfLog %XLOG_SEG_SIZE);
5246+
if (!InstallXLogFileSegment(&endLogSegNo,tmpfname, false,0, false))
5247+
elog(ERROR,"InstallXLogFileSegment should not have failed");
52015248

5202-
/* Create .ready file only when neither .ready nor .done files exist */
5203-
if (XLogArchivingActive())
5249+
/*
5250+
* Make a .partial copy for the archive (unless the original file was
5251+
* already archived)
5252+
*/
5253+
if (XLogArchivingActive()&&XLogArchiveIsBusy(xlogfname))
52045254
{
5205-
XLogFileName(xlogfname,endTLI,endLogSegNo);
5206-
XLogArchiveCheckDone(xlogfname);
5255+
charpartialfname[MAXFNAMELEN];
5256+
5257+
snprintf(partialfname,MAXFNAMELEN,"%s.partial",xlogfname);
5258+
5259+
/* Make sure there's no .done or .ready file for it. */
5260+
XLogArchiveCleanup(partialfname);
5261+
5262+
/*
5263+
* We copy the whole segment, not just upto the switch point.
5264+
* The portion after the switch point might be garbage, but it
5265+
* might also be valid WAL, if we stopped recovery at user's
5266+
* request before reaching the end. Better to preserve the
5267+
* file as it is, garbage and all, than lose the evidence if
5268+
* something goes wrong.
5269+
*/
5270+
(void)XLogFileCopy(partialfname,xlogfname,XLOG_SEG_SIZE);
5271+
XLogArchiveNotify(partialfname);
52075272
}
52085273
}
52095274
else
52105275
{
5276+
/*
5277+
* The switch happened at a segment boundary, so just create the next
5278+
* segment on the new timeline.
5279+
*/
52115280
booluse_existent= true;
52125281
intfd;
52135282

‎src/include/access/xlog_internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
145145
#defineIsXLogFileName(fname) \
146146
(strlen(fname) == 24 && strspn(fname, "0123456789ABCDEF") == 24)
147147

148+
/*
149+
* XLOG segment with .partial suffix. Used by pg_receivexlog and at end of
150+
* archive recovery, when we want to archive a WAL segment but it might not
151+
* be complete yet.
152+
*/
148153
#defineIsPartialXLogFileName(fname)\
149154
(strlen(fname) == 24 + strlen(".partial") &&\
150155
strspn(fname, "0123456789ABCDEF") == 24 &&\

‎src/include/postmaster/pgarch.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
#defineMIN_XFN_CHARS16
2626
#defineMAX_XFN_CHARS40
27-
#defineVALID_XFN_CHARS "0123456789ABCDEF.history.backup"
27+
#defineVALID_XFN_CHARS "0123456789ABCDEF.history.backup.partial"
2828

2929
/* ----------
3030
* Functions called from postmaster

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp