Skip to content

Commit c0f0f7e

Browse files
committed
Merge remote-tracking branch 'origin/skip_unchanged_files'
2 parents d04d314 + f533955 commit c0f0f7e

File tree

7 files changed

+121
-91
lines changed

7 files changed

+121
-91
lines changed

src/data.c

Lines changed: 77 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ typedef union DataPage
2929
char data[BLCKSZ];
3030
} DataPage;
3131

32+
static bool
33+
fileEqualCRC(const char *path1, const char *path2, bool path2_is_compressed);
34+
3235
#ifdef HAVE_LIBZ
3336
/* Implementation of zlib compression method */
3437
static int32
@@ -1092,45 +1095,52 @@ push_wal_file(const char *from_path, const char *to_path, bool is_compress,
10921095
FILE *in = NULL;
10931096
FILE *out=NULL;
10941097
char buf[XLOG_BLCKSZ];
1095-
const char *to_path_p = to_path;
1098+
const char *to_path_p;
10961099
char to_path_temp[MAXPGPATH];
10971100
int errno_temp;
10981101

10991102
#ifdef HAVE_LIBZ
11001103
char gz_to_path[MAXPGPATH];
11011104
gzFile gz_out = NULL;
1105+
if (is_compress)
1106+
{
1107+
snprintf(gz_to_path, sizeof(gz_to_path), "%s.gz", to_path);
1108+
to_path_p = gz_to_path;
1109+
}
1110+
else
11021111
#endif
1112+
to_path_p = to_path;
11031113

11041114
/* open file for read */
11051115
in = fopen(from_path, PG_BINARY_R);
11061116
if (in == NULL)
11071117
elog(ERROR, "Cannot open source WAL file \"%s\": %s", from_path,
11081118
strerror(errno));
11091119

1120+
/* Check if possible to skip copying */
1121+
if (fileExists(to_path_p))
1122+
{
1123+
if (fileEqualCRC(from_path, to_path_p, is_compress))
1124+
return;
1125+
/* Do not copy and do not rise error. Just quit as normal. */
1126+
else if (!overwrite)
1127+
elog(ERROR, "WAL segment \"%s\" already exists.", to_path_p);
1128+
}
1129+
11101130
/* open backup file for write */
11111131
#ifdef HAVE_LIBZ
11121132
if (is_compress)
11131133
{
1114-
snprintf(gz_to_path, sizeof(gz_to_path), "%s.gz", to_path);
1115-
1116-
if (!overwrite && fileExists(gz_to_path))
1117-
elog(ERROR, "WAL segment \"%s\" already exists.", gz_to_path);
1118-
11191134
snprintf(to_path_temp, sizeof(to_path_temp), "%s.partial", gz_to_path);
11201135

11211136
gz_out = gzopen(to_path_temp, PG_BINARY_W);
11221137
if (gzsetparams(gz_out, compress_level, Z_DEFAULT_STRATEGY) != Z_OK)
11231138
elog(ERROR, "Cannot set compression level %d to file \"%s\": %s",
11241139
compress_level, to_path_temp, get_gz_error(gz_out, errno));
1125-
1126-
to_path_p = gz_to_path;
11271140
}
11281141
else
11291142
#endif
11301143
{
1131-
if (!overwrite && fileExists(to_path))
1132-
elog(ERROR, "WAL segment \"%s\" already exists.", to_path);
1133-
11341144
snprintf(to_path_temp, sizeof(to_path_temp), "%s.partial", to_path);
11351145

11361146
out = fopen(to_path_temp, PG_BINARY_W);
@@ -1408,75 +1418,13 @@ get_wal_file(const char *from_path, const char *to_path)
14081418
* but created in process of backup, such as stream XLOG files,
14091419
* PG_TABLESPACE_MAP_FILE and PG_BACKUP_LABEL_FILE.
14101420
*/
1411-
bool
1421+
void
14121422
calc_file_checksum(pgFile *file)
14131423
{
1414-
FILE *in;
1415-
size_t read_len = 0;
1416-
int errno_tmp;
1417-
char buf[BLCKSZ];
1418-
struct stat st;
1419-
pg_crc32 crc;
1420-
14211424
Assert(S_ISREG(file->mode));
1422-
INIT_TRADITIONAL_CRC32(crc);
1423-
1424-
/* reset size summary */
1425-
file->read_size = 0;
1426-
file->write_size = 0;
1427-
1428-
/* open backup mode file for read */
1429-
in = fopen(file->path, PG_BINARY_R);
1430-
if (in == NULL)
1431-
{
1432-
FIN_TRADITIONAL_CRC32(crc);
1433-
file->crc = crc;
1434-
1435-
/* maybe deleted, it's not error */
1436-
if (errno == ENOENT)
1437-
return false;
1438-
1439-
elog(ERROR, "cannot open source file \"%s\": %s", file->path,
1440-
strerror(errno));
1441-
}
1442-
1443-
/* stat source file to change mode of destination file */
1444-
if (fstat(fileno(in), &st) == -1)
1445-
{
1446-
fclose(in);
1447-
elog(ERROR, "cannot stat \"%s\": %s", file->path,
1448-
strerror(errno));
1449-
}
1450-
1451-
for (;;)
1452-
{
1453-
read_len = fread(buf, 1, sizeof(buf), in);
1454-
1455-
if(read_len == 0)
1456-
break;
1457-
1458-
/* update CRC */
1459-
COMP_TRADITIONAL_CRC32(crc, buf, read_len);
1460-
1461-
file->write_size += read_len;
1462-
file->read_size += read_len;
1463-
}
1464-
1465-
errno_tmp = errno;
1466-
if (!feof(in))
1467-
{
1468-
fclose(in);
1469-
elog(ERROR, "cannot read backup mode file \"%s\": %s",
1470-
file->path, strerror(errno_tmp));
1471-
}
1472-
1473-
/* finish CRC calculation and store into pgFile */
1474-
FIN_TRADITIONAL_CRC32(crc);
1475-
file->crc = crc;
1476-
1477-
fclose(in);
14781425

1479-
return true;
1426+
file->crc = pgFileGetCRC(file->path, false, false, &file->read_size);
1427+
file->write_size = file->read_size;
14801428
}
14811429

14821430
/*
@@ -1724,3 +1672,56 @@ check_file_pages(pgFile *file, XLogRecPtr stop_lsn,
17241672

17251673
return is_valid;
17261674
}
1675+
1676+
static bool
1677+
fileEqualCRC(const char *path1, const char *path2, bool path2_is_compressed)
1678+
{
1679+
pg_crc32 crc1;
1680+
pg_crc32 crc2;
1681+
1682+
/* Get checksum of backup file */
1683+
#ifdef HAVE_LIBZ
1684+
if (path2_is_compressed)
1685+
{
1686+
char buf [1024];
1687+
gzFile gz_in = NULL;
1688+
1689+
INIT_CRC32C(crc2);
1690+
gz_in = gzopen(path2, PG_BINARY_R);
1691+
if (gz_in == NULL)
1692+
/* File cannot be read */
1693+
elog(ERROR,
1694+
"Cannot compare WAL file \"%s\" with compressed \"%s\"",
1695+
path1, path2);
1696+
1697+
for (;;)
1698+
{
1699+
size_t read_len = 0;
1700+
read_len = gzread(gz_in, buf, sizeof(buf));
1701+
if (read_len != sizeof(buf) && !gzeof(gz_in))
1702+
/* An error occurred while reading the file */
1703+
elog(ERROR,
1704+
"Cannot compare WAL file \"%s\" with compressed \"%s\"",
1705+
path1, path2);
1706+
1707+
COMP_CRC32C(crc2, buf, read_len);
1708+
if (gzeof(gz_in) || read_len == 0)
1709+
break;
1710+
}
1711+
FIN_CRC32C(crc2);
1712+
1713+
if (gzclose(gz_in) != 0)
1714+
elog(ERROR, "Cannot close compressed WAL file \"%s\": %s",
1715+
path2, get_gz_error(gz_in, errno));
1716+
}
1717+
else
1718+
#endif
1719+
{
1720+
crc2 = pgFileGetCRC(path2, false, true, NULL);
1721+
}
1722+
1723+
/* Get checksum of original file */
1724+
crc1 = pgFileGetCRC(path1, false, true, NULL);
1725+
1726+
return EQ_CRC32C(crc1, crc2);
1727+
}

src/dir.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -259,36 +259,55 @@ pgFileDelete(pgFile *file)
259259
}
260260

261261
pg_crc32
262-
pgFileGetCRC(const char *file_path, bool use_crc32c)
262+
pgFileGetCRC(const char *file_path, bool use_crc32c, bool raise_on_deleted,
263+
size_t *bytes_read)
263264
{
264265
FILE *fp;
265266
pg_crc32 crc = 0;
266267
char buf[1024];
267268
size_t len;
269+
size_t total = 0;
268270
int errno_tmp;
269271

272+
INIT_FILE_CRC32(use_crc32c, crc);
273+
270274
/* open file in binary read mode */
271275
fp = fopen(file_path, PG_BINARY_R);
272276
if (fp == NULL)
273-
elog(ERROR, "cannot open file \"%s\": %s",
274-
file_path, strerror(errno));
277+
{
278+
if (!raise_on_deleted && errno == ENOENT)
279+
{
280+
FIN_FILE_CRC32(use_crc32c, crc);
281+
return crc;
282+
}
283+
else
284+
elog(ERROR, "cannot open file \"%s\": %s",
285+
file_path, strerror(errno));
286+
}
275287

276-
/* calc CRC of backup file */
277-
INIT_FILE_CRC32(use_crc32c, crc);
278-
while ((len = fread(buf, 1, sizeof(buf), fp)) == sizeof(buf))
288+
/* calc CRC of file */
289+
for (;;)
279290
{
280291
if (interrupted)
281292
elog(ERROR, "interrupted during CRC calculation");
293+
294+
len = fread(buf, 1, sizeof(buf), fp);
295+
if(len == 0)
296+
break;
297+
/* update CRC */
282298
COMP_FILE_CRC32(use_crc32c, crc, buf, len);
299+
total += len;
283300
}
301+
302+
if (bytes_read)
303+
*bytes_read = total;
304+
284305
errno_tmp = errno;
285306
if (!feof(fp))
286307
elog(WARNING, "cannot read \"%s\": %s", file_path,
287308
strerror(errno_tmp));
288-
if (len > 0)
289-
COMP_FILE_CRC32(use_crc32c, crc, buf, len);
290-
FIN_FILE_CRC32(use_crc32c, crc);
291309

310+
FIN_FILE_CRC32(use_crc32c, crc);
292311
fclose(fp);
293312

294313
return crc;

src/merge.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ merge_files(void *arg)
524524
* do that.
525525
*/
526526
file->write_size = pgFileSize(to_path_tmp);
527-
file->crc = pgFileGetCRC(to_path_tmp, false);
527+
file->crc = pgFileGetCRC(to_path_tmp, false, true, NULL);
528528
}
529529
}
530530
else

src/pg_probackup.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,8 @@ extern pgFile *pgFileNew(const char *path, bool omit_symlink);
531531
extern pgFile *pgFileInit(const char *path);
532532
extern void pgFileDelete(pgFile *file);
533533
extern void pgFileFree(void *file);
534-
extern pg_crc32 pgFileGetCRC(const char *file_path, bool use_crc32c);
534+
extern pg_crc32 pgFileGetCRC(const char *file_path, bool use_crc32c,
535+
bool raise_on_deleted, size_t *bytes_read);
535536
extern int pgFileComparePath(const void *f1, const void *f2);
536537
extern int pgFileComparePathDesc(const void *f1, const void *f2);
537538
extern int pgFileCompareLinked(const void *f1, const void *f2);
@@ -552,7 +553,7 @@ extern void push_wal_file(const char *from_path, const char *to_path,
552553
bool is_compress, bool overwrite);
553554
extern void get_wal_file(const char *from_path, const char *to_path);
554555

555-
extern bool calc_file_checksum(pgFile *file);
556+
extern void calc_file_checksum(pgFile *file);
556557

557558
extern bool check_file_pages(pgFile* file,
558559
XLogRecPtr stop_lsn,

src/util.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ set_min_recovery_point(pgFile *file, const char *backup_path, XLogRecPtr stop_ba
334334
writeControlFile(&ControlFile, fullpath);
335335

336336
/* Update pg_control checksum in backup_list */
337-
file->crc = pgFileGetCRC(fullpath, false);
337+
file->crc = pgFileGetCRC(fullpath, false, true, NULL);
338338

339339
pg_free(buffer);
340340
}

src/validate.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ pgBackupValidateFiles(void *arg)
224224
* To avoid this problem we need to use different algorithm, CRC-32 in
225225
* this case.
226226
*/
227-
crc = pgFileGetCRC(file->path, arguments->backup_version <= 20021);
227+
crc = pgFileGetCRC(file->path, arguments->backup_version <= 20021,
228+
true, NULL);
228229
if (crc != file->crc)
229230
{
230231
elog(WARNING, "Invalid CRC of backup file \"%s\" : %X. Expected %X",

tests/archive.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import os
2+
import shutil
3+
import gzip
24
import unittest
35
from .helpers.ptrack_helpers import ProbackupTest, ProbackupException, archive_script
46
from datetime import datetime, timedelta
@@ -325,7 +327,13 @@ def test_arhive_push_file_exists(self):
325327
)
326328
self.assertFalse('pg_probackup archive-push completed successfully' in log_content)
327329

328-
os.remove(file)
330+
wal_src = os.path.join(node.data_dir, 'pg_wal', '000000010000000000000001')
331+
if self.archive_compress:
332+
with open(wal_src, 'rb') as f_in, gzip.open(file, 'wb', compresslevel=1) as f_out:
333+
shutil.copyfileobj(f_in, f_out)
334+
else:
335+
shutil.copyfile(wal_src, file)
336+
329337
self.switch_wal_segment(node)
330338
sleep(5)
331339

0 commit comments

Comments
 (0)