mirror of
https://github.com/postgres/postgres.git
synced 2025-05-06 19:59:18 +03:00
When performing a base backup, check for read errors.
The old code didn't differentiate between a read error and a concurrent truncation. fread reports both of these by returning 0; you have to use feof() or ferror() to distinguish between them, which this code did not do. It might be a better idea to use read() rather than fread() here, so that we can display a less-generic error message, but I'm not sure that would qualify as a back-patchable bug fix, so just do this much for now. Jeevan Chalke, reviewed by Jeevan Ladhe and by me. Discussion: http://postgr.es/m/CA+TgmobG4ywMzL5oQq2a8YKp8x2p3p1LOMMcGqpS7aekT9+ETA@mail.gmail.com
This commit is contained in:
parent
af28744288
commit
61c65cce40
@ -90,6 +90,18 @@ static char *statrelpath = NULL;
|
|||||||
*/
|
*/
|
||||||
#define THROTTLING_FREQUENCY 8
|
#define THROTTLING_FREQUENCY 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks whether we encountered any error in fread(). fread() doesn't give
|
||||||
|
* any clue what has happened, so we check with ferror(). Also, neither
|
||||||
|
* fread() nor ferror() set errno, so we just throw a generic error.
|
||||||
|
*/
|
||||||
|
#define CHECK_FREAD_ERROR(fp, filename) \
|
||||||
|
do { \
|
||||||
|
if (ferror(fp)) \
|
||||||
|
ereport(ERROR, \
|
||||||
|
(errmsg("could not read from file \"%s\"", filename))); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/* The actual number of bytes, transfer of which may cause sleep. */
|
/* The actual number of bytes, transfer of which may cause sleep. */
|
||||||
static uint64 throttling_sample;
|
static uint64 throttling_sample;
|
||||||
|
|
||||||
@ -550,6 +562,8 @@ perform_base_backup(basebackup_options *opt)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK_FREAD_ERROR(fp, pathbuf);
|
||||||
|
|
||||||
if (len != wal_segment_size)
|
if (len != wal_segment_size)
|
||||||
{
|
{
|
||||||
CheckXLogRemoved(segno, tli);
|
CheckXLogRemoved(segno, tli);
|
||||||
@ -1487,6 +1501,20 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
|
|||||||
|
|
||||||
if (fread(buf + BLCKSZ * i, 1, BLCKSZ, fp) != BLCKSZ)
|
if (fread(buf + BLCKSZ * i, 1, BLCKSZ, fp) != BLCKSZ)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* If we hit end-of-file, a concurrent
|
||||||
|
* truncation must have occurred, so break out
|
||||||
|
* of this loop just as if the initial fread()
|
||||||
|
* returned 0. We'll drop through to the same
|
||||||
|
* code that handles that case. (We must fix
|
||||||
|
* up cnt first, though.)
|
||||||
|
*/
|
||||||
|
if (feof(fp))
|
||||||
|
{
|
||||||
|
cnt = BLCKSZ * i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode_for_file_access(),
|
(errcode_for_file_access(),
|
||||||
errmsg("could not reread block %d of file \"%s\": %m",
|
errmsg("could not reread block %d of file \"%s\": %m",
|
||||||
@ -1538,7 +1566,7 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
|
|||||||
len += cnt;
|
len += cnt;
|
||||||
throttle(cnt);
|
throttle(cnt);
|
||||||
|
|
||||||
if (len >= statbuf->st_size)
|
if (feof(fp) || len >= statbuf->st_size)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Reached end of file. The file could be longer, if it was
|
* Reached end of file. The file could be longer, if it was
|
||||||
@ -1549,6 +1577,8 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK_FREAD_ERROR(fp, readfilename);
|
||||||
|
|
||||||
/* If the file was truncated while we were sending it, pad it with zeros */
|
/* If the file was truncated while we were sending it, pad it with zeros */
|
||||||
if (len < statbuf->st_size)
|
if (len < statbuf->st_size)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user