Skip to content

Commit f5e7e33

Browse files
committed
[Issue #66] Correctly handle zero-sized nonedata files during incremental restore
1 parent 9f227cc commit f5e7e33

File tree

3 files changed

+37
-20
lines changed

3 files changed

+37
-20
lines changed

src/data.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ backup_non_data_file(pgFile *file, pgFile *prev_file,
711711
}
712712

713713
/*
714-
* If non-data file exists in previous backup
714+
* If nonedata file exists in previous backup
715715
* and its mtime is less than parent backup start time ... */
716716
if (prev_file && file->exists_in_prev &&
717717
file->mtime <= parent_backup_time)
@@ -1136,7 +1136,7 @@ restore_non_data_file_internal(FILE *in, FILE *out, pgFile *file,
11361136

11371137
/* check for interrupt */
11381138
if (interrupted || thread_interrupted)
1139-
elog(ERROR, "Interrupted during non-data file restore");
1139+
elog(ERROR, "Interrupted during nonedata file restore");
11401140

11411141
read_len = fread(buf, 1, STDIO_BUFSIZE, in);
11421142

@@ -1165,7 +1165,6 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
11651165
pgFile *dest_file, FILE *out, const char *to_fullpath,
11661166
bool already_exists)
11671167
{
1168-
// int i;
11691168
char from_root[MAXPGPATH];
11701169
char from_fullpath[MAXPGPATH];
11711170
FILE *in = NULL;
@@ -1203,14 +1202,19 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
12031202
*/
12041203
if (!tmp_file)
12051204
{
1206-
elog(ERROR, "Failed to locate non-data file \"%s\" in backup %s",
1205+
elog(ERROR, "Failed to locate nonedata file \"%s\" in backup %s",
12071206
dest_file->rel_path, base36enc(tmp_backup->start_time));
12081207
continue;
12091208
}
12101209

12111210
/* Full copy is found and it is null sized, nothing to do here */
12121211
if (tmp_file->write_size == 0)
1212+
{
1213+
/* In case of incremental restore truncate file just to be safe */
1214+
if (already_exists && fio_ftruncate(out, 0))
1215+
elog(ERROR, "Cannot truncate file \"%s\": %s", strerror(errno));
12131216
return 0;
1217+
}
12141218

12151219
/* Full copy is found */
12161220
if (tmp_file->write_size > 0)
@@ -1222,14 +1226,14 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
12221226

12231227
/* sanity */
12241228
if (!tmp_backup)
1225-
elog(ERROR, "Failed to found a backup containing full copy of non-data file \"%s\"",
1229+
elog(ERROR, "Failed to locate a backup containing full copy of nonedata file \"%s\"",
12261230
to_fullpath);
12271231

12281232
if (!tmp_file)
1229-
elog(ERROR, "Failed to locate a full copy of non-data file \"%s\"", to_fullpath);
1233+
elog(ERROR, "Failed to locate a full copy of nonedata file \"%s\"", to_fullpath);
12301234

12311235
if (tmp_file->write_size <= 0)
1232-
elog(ERROR, "Full copy of non-data file has invalid size. "
1236+
elog(ERROR, "Full copy of nonedata file has invalid size. "
12331237
"Metadata corruption in backup %s in file: \"%s\"",
12341238
base36enc(tmp_backup->start_time), to_fullpath);
12351239

@@ -1245,6 +1249,10 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
12451249
to_fullpath);
12461250
return 0;
12471251
}
1252+
1253+
/* Checksum mismatch, truncate file and overwrite it */
1254+
if (fio_ftruncate(out, 0))
1255+
elog(ERROR, "Cannot truncate file \"%s\": %s", strerror(errno));
12481256
}
12491257

12501258
if (tmp_file->external_dir_num == 0)
@@ -1264,7 +1272,7 @@ restore_non_data_file(parray *parent_chain, pgBackup *dest_backup,
12641272
elog(ERROR, "Cannot open backup file \"%s\": %s", from_fullpath,
12651273
strerror(errno));
12661274

1267-
/* disable stdio buffering for non-data files */
1275+
/* disable stdio buffering for nonedata files */
12681276
setvbuf(in, NULL, _IONBF, BUFSIZ);
12691277

12701278
/* do actual work */
@@ -1793,7 +1801,7 @@ get_checksum_map(const char *fullpath, uint32 checksum_version,
17931801
char in_buf[STDIO_BUFSIZE];
17941802

17951803
/* open file */
1796-
in = fopen(fullpath, PG_BINARY_R);
1804+
in = fopen(fullpath, "r+");
17971805
if (!in)
17981806
elog(ERROR, "Cannot open source file \"%s\": %s", fullpath, strerror(errno));
17991807

@@ -1864,7 +1872,7 @@ get_lsn_map(const char *fullpath, uint32 checksum_version,
18641872
Assert(shift_lsn > 0);
18651873

18661874
/* open file */
1867-
in = fopen(fullpath, PG_BINARY_R);
1875+
in = fopen(fullpath, "r+");
18681876
if (!in)
18691877
elog(ERROR, "Cannot open source file \"%s\": %s", fullpath, strerror(errno));
18701878

src/merge.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,7 +1342,7 @@ merge_non_data_file(parray *parent_chain, pgBackup *full_backup,
13421342
*/
13431343
if (!from_file)
13441344
{
1345-
elog(ERROR, "Failed to locate non-data file \"%s\" in backup %s",
1345+
elog(ERROR, "Failed to locate nonedata file \"%s\" in backup %s",
13461346
dest_file->rel_path, base36enc(from_backup->start_time));
13471347
continue;
13481348
}
@@ -1353,11 +1353,11 @@ merge_non_data_file(parray *parent_chain, pgBackup *full_backup,
13531353

13541354
/* sanity */
13551355
if (!from_backup)
1356-
elog(ERROR, "Failed to found a backup containing full copy of non-data file \"%s\"",
1356+
elog(ERROR, "Failed to found a backup containing full copy of nonedata file \"%s\"",
13571357
dest_file->rel_path);
13581358

13591359
if (!from_file)
1360-
elog(ERROR, "Failed to locate a full copy of non-data file \"%s\"", dest_file->rel_path);
1360+
elog(ERROR, "Failed to locate a full copy of nonedata file \"%s\"", dest_file->rel_path);
13611361

13621362
/* set path to source file */
13631363
if (from_file->external_dir_num)

src/restore.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -470,8 +470,8 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
470470
base36enc(dest_backup->start_time),
471471
(uint32) (redo.lsn >> 32), (uint32) redo.lsn, redo.tli);
472472
else
473-
elog(INFO, "Destination directory redo point %X/%X on tli %i is within reach of "
474-
"backup %s with Stop LSN %X/%X on tli %i, incremental restore in 'lsn' mode is possible",
473+
elog(INFO, "Destination directory redo point %X/%X on tli %i is "
474+
"within reach of backup %s with Stop LSN %X/%X on tli %i",
475475
(uint32) (redo.lsn >> 32), (uint32) redo.lsn, redo.tli,
476476
base36enc(tmp_backup->start_time),
477477
(uint32) (tmp_backup->stop_lsn >> 32), (uint32) tmp_backup->stop_lsn,
@@ -1118,11 +1118,20 @@ restore_files(void *arg)
11181118
}
11191119
}
11201120

1121-
/* open destination file */
1122-
if (already_exists)
1123-
out = fio_fopen(to_fullpath, PG_BINARY_R "+", FIO_DB_HOST);
1124-
else
1121+
/*
1122+
* Open dest file and truncate it to zero, if destination
1123+
* file already exists and dest file size is zero, or
1124+
* if file do not exist
1125+
*/
1126+
if ((already_exists && dest_file->write_size == 0) || !already_exists)
11251127
out = fio_fopen(to_fullpath, PG_BINARY_W, FIO_DB_HOST);
1128+
/*
1129+
* If file already exists and dest size is not zero,
1130+
* then open it for reading and writing.
1131+
*/
1132+
else
1133+
out = fio_fopen(to_fullpath, PG_BINARY_R "+", FIO_DB_HOST);
1134+
11261135
if (out == NULL)
11271136
elog(ERROR, "Cannot open restore target file \"%s\": %s",
11281137
to_fullpath, strerror(errno));
@@ -1158,7 +1167,7 @@ restore_files(void *arg)
11581167
/* disable stdio buffering for local destination nonedata file */
11591168
if (!fio_is_remote_file(out))
11601169
setvbuf(out, NULL, _IONBF, BUFSIZ);
1161-
/* Destination file is non-data file */
1170+
/* Destination file is nonedata file */
11621171
arguments->restored_bytes += restore_non_data_file(arguments->parent_chain,
11631172
arguments->dest_backup, dest_file, out, to_fullpath,
11641173
already_exists);

0 commit comments

Comments
 (0)