Skip to content

Commit 025584a

Browse files
committed
Change how a base backup decides which files have checksums.
Previously, it thought that any plain file located under global, base, or a tablespace directory had checksums unless it was in a short list of excluded files. Now, it thinks that files in those directories have checksums if parse_filename_for_nontemp_relation says that they are relation files. (Temporary relation files don't matter because they're excluded from the backup anyway.) This changes the behavior if you have stray files not managed by PostgreSQL in the relevant directories. Previously, you'd get some kind of checksum-related complaint if such files existed, assuming that the cluster had checksums enabled and that the base backup wasn't run with NOVERIFY_CHECKSUMS. Now, you won't get those complaints any more. That seems like an improvement to me, because those files were presumably not created by PostgreSQL and so there is no reason to think that they would be checksummed like a PostgreSQL relation file. (If we want to complain about such files, we should complain about them existing at all, not just about their checksums.) The point of this change is to make the code more consistent. sendDir() was already calling parse_filename_for_nontemp_relation() as part of an effort to determine which files to include in the backup. So, it already had the information about whether a certain file was a relation file. sendFile() then used a separate method, embodied in is_checksummed_file(), to make what is essentially the same determination. It's better not to make the same decision using two different methods, especially in closely-related code. Patch by me. Reviewed by Dilip Kumar and Álvaro Herrera. Thanks also to Jakub Wartak and Peter Eisentraut for comments, suggestions, and testing on the larger patch set of which this is a part. Discussion: http://postgr.es/m/CAFiTN-snhaKkWhi2Gz5i3cZeKefun6sYL==wBoqqnTXxX4_mFA@mail.gmail.com Discussion: http://postgr.es/m/202311141312.u4qx5gtpvfq3@alvherre.pgsql
1 parent 519fc1b commit 025584a

File tree

1 file changed

+55
-117
lines changed

1 file changed

+55
-117
lines changed

src/backend/backup/basebackup.c

Lines changed: 55 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@ static int64 sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeo
8282
backup_manifest_info *manifest, Oid spcoid);
8383
static bool sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
8484
struct stat *statbuf, bool missing_ok,
85-
Oid dboid, Oid spcoid,
85+
Oid dboid, Oid spcoid, RelFileNumber relfilenumber,
86+
unsigned segno,
8687
backup_manifest_info *manifest);
8788
static off_t read_file_data_into_buffer(bbsink *sink,
8889
const char *readfilename, int fd,
@@ -104,7 +105,6 @@ static void convert_link_to_directory(const char *pathbuf, struct stat *statbuf)
104105
static void perform_base_backup(basebackup_options *opt, bbsink *sink);
105106
static void parse_basebackup_options(List *options, basebackup_options *opt);
106107
static int compareWalFileNames(const ListCell *a, const ListCell *b);
107-
static bool is_checksummed_file(const char *fullpath, const char *filename);
108108
static int basebackup_read_file(int fd, char *buf, size_t nbytes, off_t offset,
109109
const char *filename, bool partial_read_ok);
110110

@@ -213,23 +213,6 @@ static const struct exclude_list_item excludeFiles[] =
213213
{NULL, false}
214214
};
215215

216-
/*
217-
* List of files excluded from checksum validation.
218-
*
219-
* Note: this list should be kept in sync with what pg_checksums.c
220-
* includes.
221-
*/
222-
static const struct exclude_list_item noChecksumFiles[] = {
223-
{"pg_control", false},
224-
{"pg_filenode.map", false},
225-
{"pg_internal.init", true},
226-
{"PG_VERSION", false},
227-
#ifdef EXEC_BACKEND
228-
{"config_exec_params", true},
229-
#endif
230-
{NULL, false}
231-
};
232-
233216
/*
234217
* Actually do a base backup for the specified tablespaces.
235218
*
@@ -356,7 +339,8 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
356339
errmsg("could not stat file \"%s\": %m",
357340
XLOG_CONTROL_FILE)));
358341
sendFile(sink, XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf,
359-
false, InvalidOid, InvalidOid, &manifest);
342+
false, InvalidOid, InvalidOid,
343+
InvalidRelFileNumber, 0, &manifest);
360344
}
361345
else
362346
{
@@ -625,7 +609,8 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
625609
errmsg("could not stat file \"%s\": %m", pathbuf)));
626610

627611
sendFile(sink, pathbuf, pathbuf, &statbuf, false,
628-
InvalidOid, InvalidOid, &manifest);
612+
InvalidOid, InvalidOid, InvalidRelFileNumber, 0,
613+
&manifest);
629614

630615
/* unconditionally mark file as archived */
631616
StatusFilePath(pathbuf, fname, ".done");
@@ -1166,7 +1151,8 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
11661151
struct stat statbuf;
11671152
int64 size = 0;
11681153
const char *lastDir; /* Split last dir from parent path. */
1169-
bool isDbDir = false; /* Does this directory contain relations? */
1154+
bool isRelationDir = false; /* Does directory contain relations? */
1155+
Oid dboid = InvalidOid;
11701156

11711157
/*
11721158
* Determine if the current path is a database directory that can contain
@@ -1193,17 +1179,23 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
11931179
strncmp(lastDir - (sizeof(TABLESPACE_VERSION_DIRECTORY) - 1),
11941180
TABLESPACE_VERSION_DIRECTORY,
11951181
sizeof(TABLESPACE_VERSION_DIRECTORY) - 1) == 0))
1196-
isDbDir = true;
1182+
{
1183+
isRelationDir = true;
1184+
dboid = atooid(lastDir + 1);
1185+
}
11971186
}
1187+
else if (strcmp(path, "./global") == 0)
1188+
isRelationDir = true;
11981189

11991190
dir = AllocateDir(path);
12001191
while ((de = ReadDir(dir, path)) != NULL)
12011192
{
12021193
int excludeIdx;
12031194
bool excludeFound;
1204-
RelFileNumber relNumber;
1205-
ForkNumber relForkNum;
1206-
unsigned segno;
1195+
RelFileNumber relfilenumber = InvalidRelFileNumber;
1196+
ForkNumber relForkNum = InvalidForkNumber;
1197+
unsigned segno = 0;
1198+
bool isRelationFile = false;
12071199

12081200
/* Skip special stuff */
12091201
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
@@ -1251,37 +1243,40 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
12511243
if (excludeFound)
12521244
continue;
12531245

1246+
/*
1247+
* If there could be non-temporary relation files in this directory,
1248+
* try to parse the filename.
1249+
*/
1250+
if (isRelationDir)
1251+
isRelationFile =
1252+
parse_filename_for_nontemp_relation(de->d_name,
1253+
&relfilenumber,
1254+
&relForkNum, &segno);
1255+
12541256
/* Exclude all forks for unlogged tables except the init fork */
1255-
if (isDbDir &&
1256-
parse_filename_for_nontemp_relation(de->d_name, &relNumber,
1257-
&relForkNum, &segno))
1257+
if (isRelationFile && relForkNum != INIT_FORKNUM)
12581258
{
1259-
/* Never exclude init forks */
1260-
if (relForkNum != INIT_FORKNUM)
1261-
{
1262-
char initForkFile[MAXPGPATH];
1259+
char initForkFile[MAXPGPATH];
12631260

1264-
/*
1265-
* If any other type of fork, check if there is an init fork
1266-
* with the same RelFileNumber. If so, the file can be
1267-
* excluded.
1268-
*/
1269-
snprintf(initForkFile, sizeof(initForkFile), "%s/%u_init",
1270-
path, relNumber);
1261+
/*
1262+
* If any other type of fork, check if there is an init fork with
1263+
* the same RelFileNumber. If so, the file can be excluded.
1264+
*/
1265+
snprintf(initForkFile, sizeof(initForkFile), "%s/%u_init",
1266+
path, relfilenumber);
12711267

1272-
if (lstat(initForkFile, &statbuf) == 0)
1273-
{
1274-
elog(DEBUG2,
1275-
"unlogged relation file \"%s\" excluded from backup",
1276-
de->d_name);
1268+
if (lstat(initForkFile, &statbuf) == 0)
1269+
{
1270+
elog(DEBUG2,
1271+
"unlogged relation file \"%s\" excluded from backup",
1272+
de->d_name);
12771273

1278-
continue;
1279-
}
1274+
continue;
12801275
}
12811276
}
12821277

12831278
/* Exclude temporary relations */
1284-
if (isDbDir && looks_like_temp_rel_name(de->d_name))
1279+
if (OidIsValid(dboid) && looks_like_temp_rel_name(de->d_name))
12851280
{
12861281
elog(DEBUG2,
12871282
"temporary relation file \"%s\" excluded from backup",
@@ -1420,8 +1415,8 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
14201415

14211416
if (!sizeonly)
14221417
sent = sendFile(sink, pathbuf, pathbuf + basepathlen + 1, &statbuf,
1423-
true, isDbDir ? atooid(lastDir + 1) : InvalidOid, spcoid,
1424-
manifest);
1418+
true, dboid, spcoid,
1419+
relfilenumber, segno, manifest);
14251420

14261421
if (sent || sizeonly)
14271422
{
@@ -1443,40 +1438,6 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
14431438
return size;
14441439
}
14451440

1446-
/*
1447-
* Check if a file should have its checksum validated.
1448-
* We validate checksums on files in regular tablespaces
1449-
* (including global and default) only, and in those there
1450-
* are some files that are explicitly excluded.
1451-
*/
1452-
static bool
1453-
is_checksummed_file(const char *fullpath, const char *filename)
1454-
{
1455-
/* Check that the file is in a tablespace */
1456-
if (strncmp(fullpath, "./global/", 9) == 0 ||
1457-
strncmp(fullpath, "./base/", 7) == 0 ||
1458-
strncmp(fullpath, "/", 1) == 0)
1459-
{
1460-
int excludeIdx;
1461-
1462-
/* Compare file against noChecksumFiles skip list */
1463-
for (excludeIdx = 0; noChecksumFiles[excludeIdx].name != NULL; excludeIdx++)
1464-
{
1465-
int cmplen = strlen(noChecksumFiles[excludeIdx].name);
1466-
1467-
if (!noChecksumFiles[excludeIdx].match_prefix)
1468-
cmplen++;
1469-
if (strncmp(filename, noChecksumFiles[excludeIdx].name,
1470-
cmplen) == 0)
1471-
return false;
1472-
}
1473-
1474-
return true;
1475-
}
1476-
else
1477-
return false;
1478-
}
1479-
14801441
/*
14811442
* Given the member, write the TAR header & send the file.
14821443
*
@@ -1491,15 +1452,14 @@ is_checksummed_file(const char *fullpath, const char *filename)
14911452
static bool
14921453
sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
14931454
struct stat *statbuf, bool missing_ok, Oid dboid, Oid spcoid,
1455+
RelFileNumber relfilenumber, unsigned segno,
14941456
backup_manifest_info *manifest)
14951457
{
14961458
int fd;
14971459
BlockNumber blkno = 0;
14981460
int checksum_failures = 0;
14991461
off_t cnt;
15001462
pgoff_t bytes_done = 0;
1501-
int segmentno = 0;
1502-
char *segmentpath;
15031463
bool verify_checksum = false;
15041464
pg_checksum_context checksum_ctx;
15051465

@@ -1525,36 +1485,14 @@ sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
15251485
*/
15261486
Assert((sink->bbs_buffer_length % BLCKSZ) == 0);
15271487

1528-
if (!noverify_checksums && DataChecksumsEnabled())
1529-
{
1530-
char *filename;
1531-
1532-
/*
1533-
* Get the filename (excluding path). As last_dir_separator()
1534-
* includes the last directory separator, we chop that off by
1535-
* incrementing the pointer.
1536-
*/
1537-
filename = last_dir_separator(readfilename) + 1;
1538-
1539-
if (is_checksummed_file(readfilename, filename))
1540-
{
1541-
verify_checksum = true;
1542-
1543-
/*
1544-
* Cut off at the segment boundary (".") to get the segment number
1545-
* in order to mix it into the checksum.
1546-
*/
1547-
segmentpath = strstr(filename, ".");
1548-
if (segmentpath != NULL)
1549-
{
1550-
segmentno = atoi(segmentpath + 1);
1551-
if (segmentno == 0)
1552-
ereport(ERROR,
1553-
(errmsg("invalid segment number %d in file \"%s\"",
1554-
segmentno, filename)));
1555-
}
1556-
}
1557-
}
1488+
/*
1489+
* If we weren't told not to verify checksums, and if checksums are
1490+
* enabled for this cluster, and if this is a relation file, then verify
1491+
* the checksum.
1492+
*/
1493+
if (!noverify_checksums && DataChecksumsEnabled() &&
1494+
RelFileNumberIsValid(relfilenumber))
1495+
verify_checksum = true;
15581496

15591497
/*
15601498
* Loop until we read the amount of data the caller told us to expect. The
@@ -1569,7 +1507,7 @@ sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
15691507
/* Try to read some more data. */
15701508
cnt = read_file_data_into_buffer(sink, readfilename, fd, bytes_done,
15711509
remaining,
1572-
blkno + segmentno * RELSEG_SIZE,
1510+
blkno + segno * RELSEG_SIZE,
15731511
verify_checksum,
15741512
&checksum_failures);
15751513

0 commit comments

Comments
 (0)