Skip to content

Commit 52d469b

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 3463dac commit 52d469b

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

src/backend/replication/basebackup.c

Lines changed: 31 additions & 10 deletions
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);
@@ -194,7 +194,7 @@ perform_base_backup(basebackup_options *opt, DIR *tblspcdir)
194194
XLOG_CONTROL_FILE)));
195195
}
196196

197-
sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf);
197+
sendFile(XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf, false);
198198
}
199199

200200
/*
@@ -715,11 +715,18 @@ sendDir(char *path, int basepathlen, bool sizeonly)
715715
}
716716
else if (S_ISREG(statbuf.st_mode))
717717
{
718-
/* Add size, rounded up to 512byte block */
719-
size += ((statbuf.st_size + 511) & ~511);
718+
bool sent = false;
719+
720720
if (!sizeonly)
721-
sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf);
722-
size += 512; /* Size of the header of the file */
721+
sent = sendFile(pathbuf, pathbuf + basepathlen + 1, &statbuf,
722+
true);
723+
724+
if (sent || sizeonly)
725+
{
726+
/* Add size, rounded up to 512byte block */
727+
size += ((statbuf.st_size + 511) & ~511);
728+
size += 512; /* Size of the header of the file */
729+
}
723730
}
724731
else
725732
ereport(WARNING,
@@ -779,9 +786,17 @@ _tarChecksum(char *header)
779786
return sum;
780787
}
781788

782-
/* Given the member, write the TAR header & send the file */
783-
static void
784-
sendFile(char *readfilename, char *tarfilename, struct stat * statbuf)
789+
/*
790+
* Given the member, write the TAR header & send the file.
791+
*
792+
* If 'missing_ok' is true, will not throw an error if the file is not found.
793+
*
794+
* Returns true if the file was successfully sent, false if 'missing_ok',
795+
* and the file did not exist.
796+
*/
797+
static bool
798+
sendFile(char *readfilename, char *tarfilename, struct stat *statbuf,
799+
bool missing_ok)
785800
{
786801
FILE *fp;
787802
char buf[TAR_SEND_SIZE];
@@ -791,9 +806,13 @@ sendFile(char *readfilename, char *tarfilename, struct stat * statbuf)
791806

792807
fp = AllocateFile(readfilename, "rb");
793808
if (fp == NULL)
809+
{
810+
if (errno == ENOENT && missing_ok)
811+
return false;
794812
ereport(ERROR,
795813
(errcode_for_file_access(),
796814
errmsg("could not open file \"%s\": %m", readfilename)));
815+
}
797816

798817
/*
799818
* Some compilers will throw a warning knowing this test can never be true
@@ -847,6 +866,8 @@ sendFile(char *readfilename, char *tarfilename, struct stat * statbuf)
847866
}
848867

849868
FreeFile(fp);
869+
870+
return true;
850871
}
851872

852873

0 commit comments

Comments
 (0)