diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c index 705383d184..f491ed7f5c 100644 --- a/src/bin/pg_rewind/file_ops.c +++ b/src/bin/pg_rewind/file_ops.c @@ -29,7 +29,6 @@ static int dstfd = -1; static char dstpath[MAXPGPATH] = ""; -static void remove_target_file(const char *path); static void create_target_dir(const char *path); static void remove_target_dir(const char *path); static void create_target_symlink(const char *path, const char *link); @@ -134,7 +133,7 @@ remove_target(file_entry_t *entry) break; case FILE_TYPE_REGULAR: - remove_target_file(entry->path); + remove_target_file(entry->path, false); break; case FILE_TYPE_SYMLINK: @@ -165,8 +164,12 @@ create_target(file_entry_t *entry) } } -static void -remove_target_file(const char *path) +/* + * Remove a file from target data directory. If missing_ok is true, it + * is fine for the target file to not exist. + */ +void +remove_target_file(const char *path, bool missing_ok) { char dstpath[MAXPGPATH]; @@ -175,8 +178,13 @@ remove_target_file(const char *path) snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path); if (unlink(dstpath) != 0) + { + if (errno == ENOENT && missing_ok) + return; + pg_fatal("could not remove file \"%s\": %s\n", dstpath, strerror(errno)); + } } void diff --git a/src/bin/pg_rewind/file_ops.h b/src/bin/pg_rewind/file_ops.h index be580ee4db..9d26cf4f77 100644 --- a/src/bin/pg_rewind/file_ops.h +++ b/src/bin/pg_rewind/file_ops.h @@ -15,6 +15,7 @@ extern void open_target_file(const char *path, bool trunc); extern void write_target_range(char *buf, off_t begin, size_t size); extern void close_target_file(void); +extern void remove_target_file(const char *path, bool missing_ok); extern void truncate_target_file(const char *path, off_t newsize); extern void create_target(file_entry_t *t); extern void remove_target(file_entry_t *t); diff --git a/src/bin/pg_rewind/libpq_fetch.c b/src/bin/pg_rewind/libpq_fetch.c index 8f8d504455..5914b15017 100644 --- a/src/bin/pg_rewind/libpq_fetch.c +++ b/src/bin/pg_rewind/libpq_fetch.c @@ -311,15 +311,19 @@ receiveFileChunks(const char *sql) chunk = PQgetvalue(res, 0, 2); /* - * It's possible that the file was deleted on remote side after we - * created the file map. In this case simply ignore it, as if it was - * not there in the first place, and move on. + * If a file has been deleted on the source, remove it on the target + * as well. Note that multiple unlink() calls may happen on the same + * file if multiple data chunks are associated with it, hence ignore + * unconditionally anything missing. If this file is not a relation + * data file, then it has been already truncated when creating the + * file chunk list at the previous execution of the filemap. */ if (PQgetisnull(res, 0, 2)) { pg_log(PG_DEBUG, "received null value for chunk for file \"%s\", file has been deleted\n", filename); + remove_target_file(filename, true); pg_free(filename); PQclear(res); continue;