mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
Fix memory and file descriptor leaks in pg_receivexlog/pg_basebackup
When the internal loop mode was added, freeing memory and closing filedescriptors before returning became important, and a few cases in the code missed that. Fujii Masao
This commit is contained in:
@ -38,6 +38,10 @@
|
|||||||
#define STREAMING_HEADER_SIZE (1+sizeof(WalDataMessageHeader))
|
#define STREAMING_HEADER_SIZE (1+sizeof(WalDataMessageHeader))
|
||||||
#define STREAMING_KEEPALIVE_SIZE (1+sizeof(PrimaryKeepaliveMessage))
|
#define STREAMING_KEEPALIVE_SIZE (1+sizeof(PrimaryKeepaliveMessage))
|
||||||
|
|
||||||
|
/* fd for currently open WAL file */
|
||||||
|
static int walfile = -1;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open a new WAL file in the specified directory. Store the name
|
* Open a new WAL file in the specified directory. Store the name
|
||||||
* (not including the full directory) in namebuf. Assumes there is
|
* (not including the full directory) in namebuf. Assumes there is
|
||||||
@ -96,6 +100,7 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not pad WAL segment %s: %s\n"),
|
fprintf(stderr, _("%s: could not pad WAL segment %s: %s\n"),
|
||||||
progname, fn, strerror(errno));
|
progname, fn, strerror(errno));
|
||||||
|
free(zerobuf);
|
||||||
close(f);
|
close(f);
|
||||||
unlink(fn);
|
unlink(fn);
|
||||||
return -1;
|
return -1;
|
||||||
@ -120,7 +125,7 @@ open_walfile(XLogRecPtr startpoint, uint32 timeline, char *basedir, char *namebu
|
|||||||
* completed writing the whole segment.
|
* completed writing the whole segment.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
close_walfile(int walfile, char *basedir, char *walname, bool segment_complete)
|
close_walfile(char *basedir, char *walname, bool segment_complete)
|
||||||
{
|
{
|
||||||
off_t currpos = lseek(walfile, 0, SEEK_CUR);
|
off_t currpos = lseek(walfile, 0, SEEK_CUR);
|
||||||
|
|
||||||
@ -142,8 +147,10 @@ close_walfile(int walfile, char *basedir, char *walname, bool segment_complete)
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not close file %s: %s\n"),
|
fprintf(stderr, _("%s: could not close file %s: %s\n"),
|
||||||
progname, walname, strerror(errno));
|
progname, walname, strerror(errno));
|
||||||
|
walfile = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
walfile = -1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Rename the .partial file only if we've completed writing the whole
|
* Rename the .partial file only if we've completed writing the whole
|
||||||
@ -270,7 +277,6 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
char current_walfile_name[MAXPGPATH];
|
char current_walfile_name[MAXPGPATH];
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
char *copybuf = NULL;
|
char *copybuf = NULL;
|
||||||
int walfile = -1;
|
|
||||||
int64 last_status = -1;
|
int64 last_status = -1;
|
||||||
XLogRecPtr blockpos = InvalidXLogRecPtr;
|
XLogRecPtr blockpos = InvalidXLogRecPtr;
|
||||||
|
|
||||||
@ -315,6 +321,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not start replication: %s\n"),
|
fprintf(stderr, _("%s: could not start replication: %s\n"),
|
||||||
progname, PQresultErrorMessage(res));
|
progname, PQresultErrorMessage(res));
|
||||||
|
PQclear(res);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
@ -341,9 +348,9 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
*/
|
*/
|
||||||
if (stream_stop && stream_stop(blockpos, timeline, false))
|
if (stream_stop && stream_stop(blockpos, timeline, false))
|
||||||
{
|
{
|
||||||
if (walfile != -1)
|
if (walfile != -1 && !close_walfile(basedir, current_walfile_name, rename_partial))
|
||||||
/* Potential error message is written by close_walfile */
|
/* Potential error message is written by close_walfile */
|
||||||
return close_walfile(walfile, basedir, current_walfile_name, rename_partial);
|
goto error;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +377,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not send feedback packet: %s"),
|
fprintf(stderr, _("%s: could not send feedback packet: %s"),
|
||||||
progname, PQerrorMessage(conn));
|
progname, PQerrorMessage(conn));
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
last_status = now;
|
last_status = now;
|
||||||
@ -421,14 +428,14 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: select() failed: %s\n"),
|
fprintf(stderr, _("%s: select() failed: %s\n"),
|
||||||
progname, strerror(errno));
|
progname, strerror(errno));
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
/* Else there is actually data on the socket */
|
/* Else there is actually data on the socket */
|
||||||
if (PQconsumeInput(conn) == 0)
|
if (PQconsumeInput(conn) == 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not receive data from WAL stream: %s\n"),
|
fprintf(stderr, _("%s: could not receive data from WAL stream: %s\n"),
|
||||||
progname, PQerrorMessage(conn));
|
progname, PQerrorMessage(conn));
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -439,7 +446,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not read copy data: %s\n"),
|
fprintf(stderr, _("%s: could not read copy data: %s\n"),
|
||||||
progname, PQerrorMessage(conn));
|
progname, PQerrorMessage(conn));
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
if (copybuf[0] == 'k')
|
if (copybuf[0] == 'k')
|
||||||
{
|
{
|
||||||
@ -451,7 +458,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: keepalive message is incorrect size: %d\n"),
|
fprintf(stderr, _("%s: keepalive message is incorrect size: %d\n"),
|
||||||
progname, r);
|
progname, r);
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -459,13 +466,13 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: unrecognized streaming header: \"%c\"\n"),
|
fprintf(stderr, _("%s: unrecognized streaming header: \"%c\"\n"),
|
||||||
progname, copybuf[0]);
|
progname, copybuf[0]);
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
if (r < STREAMING_HEADER_SIZE + 1)
|
if (r < STREAMING_HEADER_SIZE + 1)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: streaming header too small: %d\n"),
|
fprintf(stderr, _("%s: streaming header too small: %d\n"),
|
||||||
progname, r);
|
progname, r);
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract WAL location for this block */
|
/* Extract WAL location for this block */
|
||||||
@ -483,7 +490,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: received xlog record for offset %u with no file open\n"),
|
fprintf(stderr, _("%s: received xlog record for offset %u with no file open\n"),
|
||||||
progname, xlogoff);
|
progname, xlogoff);
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -494,7 +501,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: got WAL data offset %08x, expected %08x\n"),
|
fprintf(stderr, _("%s: got WAL data offset %08x, expected %08x\n"),
|
||||||
progname, xlogoff, (int) lseek(walfile, 0, SEEK_CUR));
|
progname, xlogoff, (int) lseek(walfile, 0, SEEK_CUR));
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,7 +527,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
basedir, current_walfile_name);
|
basedir, current_walfile_name);
|
||||||
if (walfile == -1)
|
if (walfile == -1)
|
||||||
/* Error logged by open_walfile */
|
/* Error logged by open_walfile */
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (write(walfile,
|
if (write(walfile,
|
||||||
@ -532,7 +539,7 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
bytes_to_write,
|
bytes_to_write,
|
||||||
current_walfile_name,
|
current_walfile_name,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write was successful, advance our position */
|
/* Write was successful, advance our position */
|
||||||
@ -544,11 +551,10 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
/* Did we reach the end of a WAL segment? */
|
/* Did we reach the end of a WAL segment? */
|
||||||
if (blockpos % XLOG_SEG_SIZE == 0)
|
if (blockpos % XLOG_SEG_SIZE == 0)
|
||||||
{
|
{
|
||||||
if (!close_walfile(walfile, basedir, current_walfile_name, false))
|
if (!close_walfile(basedir, current_walfile_name, false))
|
||||||
/* Error message written in close_walfile() */
|
/* Error message written in close_walfile() */
|
||||||
return false;
|
goto error;
|
||||||
|
|
||||||
walfile = -1;
|
|
||||||
xlogoff = 0;
|
xlogoff = 0;
|
||||||
|
|
||||||
if (stream_stop != NULL)
|
if (stream_stop != NULL)
|
||||||
@ -577,8 +583,22 @@ ReceiveXlogStream(PGconn *conn, XLogRecPtr startpos, uint32 timeline, char *sysi
|
|||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: unexpected termination of replication stream: %s\n"),
|
fprintf(stderr, _("%s: unexpected termination of replication stream: %s\n"),
|
||||||
progname, PQresultErrorMessage(res));
|
progname, PQresultErrorMessage(res));
|
||||||
return false;
|
goto error;
|
||||||
}
|
}
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
|
if (copybuf != NULL)
|
||||||
|
PQfreemem(copybuf);
|
||||||
|
if (walfile != -1 && close(walfile) != 0)
|
||||||
|
fprintf(stderr, _("%s: could not close file %s: %s\n"),
|
||||||
|
progname, current_walfile_name, strerror(errno));
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (copybuf != NULL)
|
||||||
|
PQfreemem(copybuf);
|
||||||
|
if (walfile != -1 && close(walfile) != 0)
|
||||||
|
fprintf(stderr, _("%s: could not close file %s: %s\n"),
|
||||||
|
progname, current_walfile_name, strerror(errno));
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +143,17 @@ GetConnection(void)
|
|||||||
|
|
||||||
tmpconn = PQconnectdbParams(keywords, values, true);
|
tmpconn = PQconnectdbParams(keywords, values, true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is too little memory even to allocate the PGconn object
|
||||||
|
* and PQconnectdbParams returns NULL, we call exit(1) directly.
|
||||||
|
*/
|
||||||
|
if (!tmpconn)
|
||||||
|
{
|
||||||
|
fprintf(stderr, _("%s: could not connect to server\n"),
|
||||||
|
progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
if (PQstatus(tmpconn) == CONNECTION_BAD &&
|
if (PQstatus(tmpconn) == CONNECTION_BAD &&
|
||||||
PQconnectionNeedsPassword(tmpconn) &&
|
PQconnectionNeedsPassword(tmpconn) &&
|
||||||
dbgetpassword != -1)
|
dbgetpassword != -1)
|
||||||
@ -154,8 +165,11 @@ GetConnection(void)
|
|||||||
|
|
||||||
if (PQstatus(tmpconn) != CONNECTION_OK)
|
if (PQstatus(tmpconn) != CONNECTION_OK)
|
||||||
{
|
{
|
||||||
fprintf(stderr, _("%s: could not connect to server: %s"),
|
fprintf(stderr, _("%s: could not connect to server: %s\n"),
|
||||||
progname, PQerrorMessage(tmpconn));
|
progname, PQerrorMessage(tmpconn));
|
||||||
|
PQfinish(tmpconn);
|
||||||
|
free(values);
|
||||||
|
free(keywords);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user