Skip to content

Commit ce5542d

Browse files
committed
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
1 parent d57a931 commit ce5542d

File tree

1 file changed

+31
-1
lines changed

1 file changed

+31
-1
lines changed

src/backend/replication/basebackup.c

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ static char *statrelpath = NULL;
9090
*/
9191
#define THROTTLING_FREQUENCY 8
9292

93+
/*
94+
* Checks whether we encountered any error in fread(). fread() doesn't give
95+
* any clue what has happened, so we check with ferror(). Also, neither
96+
* fread() nor ferror() set errno, so we just throw a generic error.
97+
*/
98+
#define CHECK_FREAD_ERROR(fp, filename) \
99+
do { \
100+
if (ferror(fp)) \
101+
ereport(ERROR, \
102+
(errmsg("could not read from file \"%s\"", filename))); \
103+
} while (0)
104+
93105
/* The actual number of bytes, transfer of which may cause sleep. */
94106
static uint64 throttling_sample;
95107

@@ -550,6 +562,8 @@ perform_base_backup(basebackup_options *opt)
550562
break;
551563
}
552564

565+
CHECK_FREAD_ERROR(fp, pathbuf);
566+
553567
if (len != wal_segment_size)
554568
{
555569
CheckXLogRemoved(segno, tli);
@@ -1490,6 +1504,20 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
14901504

14911505
if (fread(buf + BLCKSZ * i, 1, BLCKSZ, fp) != BLCKSZ)
14921506
{
1507+
/*
1508+
* If we hit end-of-file, a concurrent
1509+
* truncation must have occurred, so break out
1510+
* of this loop just as if the initial fread()
1511+
* returned 0. We'll drop through to the same
1512+
* code that handles that case. (We must fix
1513+
* up cnt first, though.)
1514+
*/
1515+
if (feof(fp))
1516+
{
1517+
cnt = BLCKSZ * i;
1518+
break;
1519+
}
1520+
14931521
ereport(ERROR,
14941522
(errcode_for_file_access(),
14951523
errmsg("could not reread block %d of file \"%s\": %m",
@@ -1541,7 +1569,7 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
15411569
len += cnt;
15421570
throttle(cnt);
15431571

1544-
if (len >= statbuf->st_size)
1572+
if (feof(fp) || len >= statbuf->st_size)
15451573
{
15461574
/*
15471575
* Reached end of file. The file could be longer, if it was
@@ -1552,6 +1580,8 @@ sendFile(const char *readfilename, const char *tarfilename, struct stat *statbuf
15521580
}
15531581
}
15541582

1583+
CHECK_FREAD_ERROR(fp, readfilename);
1584+
15551585
/* If the file was truncated while we were sending it, pad it with zeros */
15561586
if (len < statbuf->st_size)
15571587
{

0 commit comments

Comments
 (0)