Skip to content

Commit 36e4456

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 d57a973 commit 36e4456

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

src/backend/replication/basebackup.c

+31-10
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ typedef struct
4444

4545

4646
static int64 sendDir(char *path, int basepathlen, bool sizeonly);
47-
static void sendFile(char *readfilename, char *tarfilename,
48-
struct stat * statbuf);
47+
static bool sendFile(char *readfilename, char *tarfilename,
48+
struct stat * statbuf, bool missing_ok);
4949
static void sendFileWithContent(const char *filename, const char *content);
5050
static void _tarWriteHeader(const char *filename, const char *linktarget,
5151
struct stat * statbuf);
@@ -199,7 +199,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
199199
XLOG_CONTROL_FILE)));
200200
}
201201

202-
sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf);
202+
sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false);
203203
}
204204

205205
/*
@@ -712,11 +712,18 @@ sendDir(char *path, int basepathlen, bool sizeonly)
712712
}
713713
else if (S_ISREG(statbuf.st_mode))
714714
{
715-
/* Add size, rounded up to 512byte block */
716-
size += ((statbuf.st_size + 511) & ~511);
715+
bool sent = false;
716+
717717
if (!sizeonly)
718-
sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf);
719-
size += 512; /* Size of the header of the file */
718+
sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
719+
true);
720+
721+
if (sent || sizeonly)
722+
{
723+
/* Add size, rounded up to 512byte block */
724+
size += ((statbuf.st_size + 511) & ~511);
725+
size += 512; /* Size of the header of the file */
726+
}
720727
}
721728
else
722729
ereport(WARNING,
@@ -776,9 +783,17 @@ _tarChecksum(char *header)
776783
return sum;
777784
}
778785

779-
/* Given the member, write the TAR header & send the file */
780-
static void
781-
sendFile(char *readfilename, char *tarfilename, struct stat * statbuf)
786+
/*
787+
* Given the member, write the TAR header & send the file.
788+
*
789+
* If 'missing_ok' is true, will not throw an error if the file is not found.
790+
*
791+
* Returns true if the file was successfully sent, false if 'missing_ok',
792+
* and the file did not exist.
793+
*/
794+
static bool
795+
sendFile(char *readfilename, char *tarfilename, struct stat *statbuf,
796+
bool missing_ok)
782797
{
783798
FILE *fp;
784799
char buf[TAR_SEND_SIZE];
@@ -788,9 +803,13 @@ sendFile(char *readfilename, char *tarfilename, struct stat * statbuf)
788803

789804
fp = AllocateFile(readfilename, "rb");
790805
if (fp == NULL)
806+
{
807+
if (errno == ENOENT && missing_ok)
808+
return false;
791809
ereport(ERROR,
792810
(errcode_for_file_access(),
793811
errmsg("could not open file \"%s\": %m", readfilename)));
812+
}
794813

795814
/*
796815
* Some compilers will throw a warning knowing this test can never be true
@@ -844,6 +863,8 @@ sendFile(char *readfilename, char *tarfilename, struct stat * statbuf)
844863
}
845864

846865
FreeFile(fp);
866+
867+
return true;
847868
}
848869

849870

0 commit comments

Comments
 (0)