Refactor WAL segment copying code.

* Remove unused argument "dstfname" and related code from XLogFileCopy().

* Previously XLogFileCopy() returned a pstrdup'd string so that
InstallXLogFileSegment() used it later. Since the pstrdup'd string was never
free'd, there could be a risk of memory leak. It was almost harmless because
the startup process exited just after calling XLogFileCopy(), it existed.
This commit changes XLogFileCopy() so that it directly calls
InstallXLogFileSegment() and doesn't call pstrdup() at all. Which fixes that
memory leak problem.

* Extend InstallXLogFileSegment() so that the caller can specify the log level.
Which allows us to emit an error when InstallXLogFileSegment() fails a disk
file access like link() and rename(). Previously it was always logged with
LOG level and additionally needed to be logged with ERROR when we wanted
to treat it as an error.

Michael Paquier
This commit is contained in:
Fujii Masao 2015-06-09 03:03:24 +09:00
parent d1b958218a
commit 7abc685974
1 changed files with 17 additions and 37 deletions

View File

@ -807,7 +807,7 @@ static bool XLogCheckpointNeeded(XLogSegNo new_segno);
static void XLogWrite(XLogwrtRqst WriteRqst, bool flexible); static void XLogWrite(XLogwrtRqst WriteRqst, bool flexible);
static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath, static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
bool find_free, XLogSegNo max_segno, bool find_free, XLogSegNo max_segno,
bool use_lock); bool use_lock, int elevel);
static int XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, static int XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli,
int source, bool notexistOk); int source, bool notexistOk);
static int XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source); static int XLogFileReadAnyTLI(XLogSegNo segno, int emode, int source);
@ -3012,7 +3012,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
max_segno = logsegno + CheckPointSegments; max_segno = logsegno + CheckPointSegments;
if (!InstallXLogFileSegment(&installed_segno, tmppath, if (!InstallXLogFileSegment(&installed_segno, tmppath,
*use_existent, max_segno, *use_existent, max_segno,
use_lock)) use_lock, LOG))
{ {
/* /*
* No need for any more future segments, or InstallXLogFileSegment() * No need for any more future segments, or InstallXLogFileSegment()
@ -3041,18 +3041,16 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
/* /*
* Copy a WAL segment file in pg_xlog directory. * Copy a WAL segment file in pg_xlog directory.
* *
* dstfname destination filename
* srcfname source filename * srcfname source filename
* upto how much of the source file to copy? (the rest is filled with * upto how much of the source file to copy? (the rest is filled with
* zeros) * zeros)
* segno identify segment to install.
* *
* If dstfname is not given, the file is created with a temporary filename, * The file is first copied with a temporary filename, and then installed as
* which is returned. Both filenames are relative to the pg_xlog directory. * a newly-created segment.
*
* NB: Any existing file with the same name will be overwritten!
*/ */
static char * static void
XLogFileCopy(char *dstfname, char *srcfname, int upto) XLogFileCopy(char *srcfname, int upto, XLogSegNo segno)
{ {
char srcpath[MAXPGPATH]; char srcpath[MAXPGPATH];
char tmppath[MAXPGPATH]; char tmppath[MAXPGPATH];
@ -3150,25 +3148,9 @@ XLogFileCopy(char *dstfname, char *srcfname, int upto)
CloseTransientFile(srcfd); CloseTransientFile(srcfd);
/* /* install the new file */
* Now move the segment into place with its final name. (Or just return (void) InstallXLogFileSegment(&segno, tmppath, false,
* the path to the file we created, if the caller wants to handle the rest 0, false, ERROR);
* on its own.)
*/
if (dstfname)
{
char dstpath[MAXPGPATH];
snprintf(dstpath, MAXPGPATH, XLOGDIR "/%s", dstfname);
if (rename(tmppath, dstpath) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not rename file \"%s\" to \"%s\": %m",
tmppath, dstpath)));
return NULL;
}
else
return pstrdup(tmppath);
} }
/* /*
@ -3195,6 +3177,8 @@ XLogFileCopy(char *dstfname, char *srcfname, int upto)
* place. This should be TRUE except during bootstrap log creation. The * place. This should be TRUE except during bootstrap log creation. The
* caller must *not* hold the lock at call. * caller must *not* hold the lock at call.
* *
* elevel: log level used by this routine.
*
* Returns TRUE if the file was installed successfully. FALSE indicates that * Returns TRUE if the file was installed successfully. FALSE indicates that
* max_segno limit was exceeded, or an error occurred while renaming the * max_segno limit was exceeded, or an error occurred while renaming the
* file into place. * file into place.
@ -3202,7 +3186,7 @@ XLogFileCopy(char *dstfname, char *srcfname, int upto)
static bool static bool
InstallXLogFileSegment(XLogSegNo *segno, char *tmppath, InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
bool find_free, XLogSegNo max_segno, bool find_free, XLogSegNo max_segno,
bool use_lock) bool use_lock, int elevel)
{ {
char path[MAXPGPATH]; char path[MAXPGPATH];
struct stat stat_buf; struct stat stat_buf;
@ -3247,7 +3231,7 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
{ {
if (use_lock) if (use_lock)
LWLockRelease(ControlFileLock); LWLockRelease(ControlFileLock);
ereport(LOG, ereport(elevel,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not link file \"%s\" to \"%s\" (initialization of log file): %m", errmsg("could not link file \"%s\" to \"%s\" (initialization of log file): %m",
tmppath, path))); tmppath, path)));
@ -3259,7 +3243,7 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
{ {
if (use_lock) if (use_lock)
LWLockRelease(ControlFileLock); LWLockRelease(ControlFileLock);
ereport(LOG, ereport(elevel,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not rename file \"%s\" to \"%s\" (initialization of log file): %m", errmsg("could not rename file \"%s\" to \"%s\" (initialization of log file): %m",
tmppath, path))); tmppath, path)));
@ -3748,7 +3732,7 @@ RemoveXlogFile(const char *segname, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr)
if (endlogSegNo <= recycleSegNo && if (endlogSegNo <= recycleSegNo &&
lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) && lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) &&
InstallXLogFileSegment(&endlogSegNo, path, InstallXLogFileSegment(&endlogSegNo, path,
true, recycleSegNo, true)) true, recycleSegNo, true, LOG))
{ {
ereport(DEBUG2, ereport(DEBUG2,
(errmsg("recycled transaction log file \"%s\"", (errmsg("recycled transaction log file \"%s\"",
@ -5227,8 +5211,6 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
*/ */
if (endLogSegNo == startLogSegNo) if (endLogSegNo == startLogSegNo)
{ {
char *tmpfname;
XLogFileName(xlogfname, endTLI, endLogSegNo); XLogFileName(xlogfname, endTLI, endLogSegNo);
/* /*
@ -5238,9 +5220,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
* considerations. But we should be just as tense as XLogFileInit to * considerations. But we should be just as tense as XLogFileInit to
* avoid emplacing a bogus file. * avoid emplacing a bogus file.
*/ */
tmpfname = XLogFileCopy(NULL, xlogfname, endOfLog % XLOG_SEG_SIZE); XLogFileCopy(xlogfname, endOfLog % XLOG_SEG_SIZE, endLogSegNo);
if (!InstallXLogFileSegment(&endLogSegNo, tmpfname, false, 0, false))
elog(ERROR, "InstallXLogFileSegment should not have failed");
} }
else else
{ {