Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b36805f

Browse files
committed
Don't choke on files that are removed while pg_rewind runs.
If a file is removed from the source server, while pg_rewind is running, the invocation of pg_read_binary_file() will fail. Use the just-added missing_ok option to that function, to have it return NULL instead, and handle that gracefully. And similarly for pg_ls_dir and pg_stat_file. Reported by Fujii Masao, fix by Michael Paquier.
1 parent cb2acb1 commit b36805f

File tree

1 file changed

+30
-7
lines changed

1 file changed

+30
-7
lines changed

src/bin/pg_rewind/libpq_fetch.c

+30-7
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,14 @@ libpqProcessFileList(void)
149149
sql =
150150
"WITH RECURSIVE files (path, filename, size, isdir) AS (\n"
151151
" SELECT '' AS path, filename, size, isdir FROM\n"
152-
" (SELECT pg_ls_dir('.') AS filename) AS fn,\n"
153-
" pg_stat_file(fn.filename) AS this\n"
152+
" (SELECT pg_ls_dir('.', true, false) AS filename) AS fn,\n"
153+
" pg_stat_file(fn.filename, true) AS this\n"
154154
" UNION ALL\n"
155155
" SELECT parent.path || parent.filename || '/' AS path,\n"
156156
" fn, this.size, this.isdir\n"
157157
" FROM files AS parent,\n"
158-
" pg_ls_dir(parent.path || parent.filename) AS fn,\n"
159-
" pg_stat_file(parent.path || parent.filename || '/' || fn) AS this\n"
158+
" pg_ls_dir(parent.path || parent.filename, true, false) AS fn,\n"
159+
" pg_stat_file(parent.path || parent.filename || '/' || fn, true) AS this\n"
160160
" WHERE parent.isdir = 't'\n"
161161
")\n"
162162
"SELECT path || filename, size, isdir,\n"
@@ -183,6 +183,15 @@ libpqProcessFileList(void)
183183
char *link_target = PQgetvalue(res, i, 3);
184184
file_type_t type;
185185

186+
if (PQgetisnull(res, 0, 1))
187+
{
188+
/*
189+
* The file was removed from the server while the query was
190+
* running. Ignore it.
191+
*/
192+
continue;
193+
}
194+
186195
if (link_target[0])
187196
type = FILE_TYPE_SYMLINK;
188197
else if (isdir)
@@ -259,8 +268,7 @@ receiveFileChunks(const char *sql)
259268
}
260269

261270
if (PQgetisnull(res, 0, 0) ||
262-
PQgetisnull(res, 0, 1) ||
263-
PQgetisnull(res, 0, 2))
271+
PQgetisnull(res, 0, 1))
264272
{
265273
pg_fatal("unexpected null values in result while fetching remote files\n");
266274
}
@@ -280,6 +288,21 @@ receiveFileChunks(const char *sql)
280288

281289
chunk = PQgetvalue(res, 0, 2);
282290

291+
/*
292+
* It's possible that the file was deleted on remote side after we
293+
* created the file map. In this case simply ignore it, as if it was
294+
* not there in the first place, and move on.
295+
*/
296+
if (PQgetisnull(res, 0, 2))
297+
{
298+
pg_log(PG_DEBUG,
299+
"received NULL chunk for file \"%s\", file has been deleted\n",
300+
filename);
301+
pg_free(filename);
302+
PQclear(res);
303+
continue;
304+
}
305+
283306
pg_log(PG_DEBUG, "received chunk for file \"%s\", offset %d, size %d\n",
284307
filename, chunkoff, chunksize);
285308

@@ -445,7 +468,7 @@ libpq_executeFileMap(filemap_t *map)
445468
*/
446469
sql =
447470
"SELECT path, begin, \n"
448-
" pg_read_binary_file(path, begin, len) AS chunk\n"
471+
" pg_read_binary_file(path, begin, len, true) AS chunk\n"
449472
"FROM fetchchunks\n";
450473

451474
receiveFileChunks(sql);

0 commit comments

Comments
 (0)