Skip to content

Commit 14aa55d

Browse files
committed
Fix race condition if a file is removed while pg_basebackup is running.
If a relation file was removed when the server-side counterpart of pg_basebackup was just about to open it to send it to the client, you'd get a "could not open file" error. Fix that. Backpatch to 9.1, this goes back to when pg_basebackup was introduced.
1 parent 17a7106 commit 14aa55d

File tree

1 file changed

+30
-9
lines changed

1 file changed

+30
-9
lines changed

src/backend/replication/basebackup.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ typedef struct
4343

4444

4545
static int64 sendDir(char *path, int basepathlen, bool sizeonly);
46-
static void sendFile(char *readfilename, char *tarfilename,
47-
struct stat * statbuf);
46+
static bool sendFile(char *readfilename, char *tarfilename,
47+
struct stat * statbuf, bool missing_ok);
4848
static void sendFileWithContent(const char *filename, const char *content);
4949
static void _tarWriteHeader(const char *filename, const char *linktarget,
5050
struct stat * statbuf);
@@ -692,11 +692,18 @@ sendDir(char *path, int basepathlen, bool sizeonly)
692692
}
693693
else if (S_ISREG(statbuf.st_mode))
694694
{
695-
/* Add size, rounded up to 512byte block */
696-
size += ((statbuf.st_size + 511) & ~511);
695+
bool sent = false;
696+
697697
if (!sizeonly)
698-
sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf);
699-
size += 512; /* Size of the header of the file */
698+
sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
699+
true);
700+
701+
if (sent || sizeonly)
702+
{
703+
/* Add size, rounded up to 512byte block */
704+
size += ((statbuf.st_size + 511) & ~511);
705+
size += 512; /* Size of the header of the file */
706+
}
700707
}
701708
else
702709
ereport(WARNING,
@@ -756,9 +763,17 @@ _tarChecksum(char *header)
756763
return sum;
757764
}
758765

759-
/* Given the member, write the TAR header & send the file */
760-
static void
761-
sendFile(char *readfilename, char *tarfilename, struct stat * statbuf)
766+
/*
767+
* Given the member, write the TAR header & send the file.
768+
*
769+
* If 'missing_ok' is true, will not throw an error if the file is not found.
770+
*
771+
* Returns true if the file was successfully sent, false if 'missing_ok',
772+
* and the file did not exist.
773+
*/
774+
static bool
775+
sendFile(char *readfilename, char *tarfilename, struct stat *statbuf,
776+
bool missing_ok)
762777
{
763778
FILE *fp;
764779
char buf[TAR_SEND_SIZE];
@@ -768,9 +783,13 @@ sendFile(char *readfilename, char *tarfilename, struct stat * statbuf)
768783

769784
fp = AllocateFile(readfilename, "rb");
770785
if (fp == NULL)
786+
{
787+
if (errno == ENOENT && missing_ok)
788+
return false;
771789
ereport(ERROR,
772790
(errcode_for_file_access(),
773791
errmsg("could not open file \"%s\": %m", readfilename)));
792+
}
774793

775794
/*
776795
* Some compilers will throw a warning knowing this test can never be true
@@ -824,6 +843,8 @@ sendFile(char *readfilename, char *tarfilename, struct stat * statbuf)
824843
}
825844

826845
FreeFile(fp);
846+
847+
return true;
827848
}
828849

829850

0 commit comments

Comments
 (0)