diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c index 705383d..3348c4a 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,11 @@ create_target(file_entry_t *entry) } } -static void -remove_target_file(const char *path) +/* + * Remove a file, ignoring an error if it doesn't exist and missing_ok is true. + */ +void +remove_target_file(const char *path, bool missing_ok) { char dstpath[MAXPGPATH]; @@ -174,7 +176,8 @@ remove_target_file(const char *path) return; snprintf(dstpath, sizeof(dstpath), "%s/%s", datadir_target, path); - if (unlink(dstpath) != 0) + if (unlink(dstpath) != 0 && + !(errno == ENOENT && missing_ok)) pg_fatal("could not remove file \"%s\": %s\n", dstpath, strerror(errno)); } diff --git a/src/bin/pg_rewind/file_ops.h b/src/bin/pg_rewind/file_ops.h index be580ee..9d26cf4 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 d1726d1..114caf3 100644 --- a/src/bin/pg_rewind/libpq_fetch.c +++ b/src/bin/pg_rewind/libpq_fetch.c @@ -304,15 +304,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;