backup_manifest_info *manifest, Oid spcoid);
static bool sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
struct stat *statbuf, bool missing_ok,
- Oid dboid, Oid spcoid,
+ Oid dboid, Oid spcoid, RelFileNumber relfilenumber,
+ unsigned segno,
backup_manifest_info *manifest);
static off_t read_file_data_into_buffer(bbsink *sink,
const char *readfilename, int fd,
static void perform_base_backup(basebackup_options *opt, bbsink *sink);
static void parse_basebackup_options(List *options, basebackup_options *opt);
static int compareWalFileNames(const ListCell *a, const ListCell *b);
-static bool is_checksummed_file(const char *fullpath, const char *filename);
static int basebackup_read_file(int fd, char *buf, size_t nbytes, off_t offset,
const char *filename, bool partial_read_ok);
{NULL, false}
};
-/*
- * List of files excluded from checksum validation.
- *
- * Note: this list should be kept in sync with what pg_checksums.c
- * includes.
- */
-static const struct exclude_list_item noChecksumFiles[] = {
- {"pg_control", false},
- {"pg_filenode.map", false},
- {"pg_internal.init", true},
- {"PG_VERSION", false},
-#ifdef EXEC_BACKEND
- {"config_exec_params", true},
-#endif
- {NULL, false}
-};
-
/*
* Actually do a base backup for the specified tablespaces.
*
errmsg("could not stat file \"%s\": %m",
XLOG_CONTROL_FILE)));
sendFile(sink, XLOG_CONTROL_FILE, XLOG_CONTROL_FILE, &statbuf,
- false, InvalidOid, InvalidOid, &manifest);
+ false, InvalidOid, InvalidOid,
+ InvalidRelFileNumber, 0, &manifest);
}
else
{
errmsg("could not stat file \"%s\": %m", pathbuf)));
sendFile(sink, pathbuf, pathbuf, &statbuf, false,
- InvalidOid, InvalidOid, &manifest);
+ InvalidOid, InvalidOid, InvalidRelFileNumber, 0,
+ &manifest);
/* unconditionally mark file as archived */
StatusFilePath(pathbuf, fname, ".done");
struct stat statbuf;
int64 size = 0;
const char *lastDir; /* Split last dir from parent path. */
- bool isDbDir = false; /* Does this directory contain relations? */
+ bool isRelationDir = false; /* Does directory contain relations? */
+ Oid dboid = InvalidOid;
/*
* Determine if the current path is a database directory that can contain
strncmp(lastDir - (sizeof(TABLESPACE_VERSION_DIRECTORY) - 1),
TABLESPACE_VERSION_DIRECTORY,
sizeof(TABLESPACE_VERSION_DIRECTORY) - 1) == 0))
- isDbDir = true;
+ {
+ isRelationDir = true;
+ dboid = atooid(lastDir + 1);
+ }
}
+ else if (strcmp(path, "./global") == 0)
+ isRelationDir = true;
dir = AllocateDir(path);
while ((de = ReadDir(dir, path)) != NULL)
{
int excludeIdx;
bool excludeFound;
- RelFileNumber relNumber;
- ForkNumber relForkNum;
- unsigned segno;
+ RelFileNumber relfilenumber = InvalidRelFileNumber;
+ ForkNumber relForkNum = InvalidForkNumber;
+ unsigned segno = 0;
+ bool isRelationFile = false;
/* Skip special stuff */
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0)
if (excludeFound)
continue;
+ /*
+ * If there could be non-temporary relation files in this directory,
+ * try to parse the filename.
+ */
+ if (isRelationDir)
+ isRelationFile =
+ parse_filename_for_nontemp_relation(de->d_name,
+ &relfilenumber,
+ &relForkNum, &segno);
+
/* Exclude all forks for unlogged tables except the init fork */
- if (isDbDir &&
- parse_filename_for_nontemp_relation(de->d_name, &relNumber,
- &relForkNum, &segno))
+ if (isRelationFile && relForkNum != INIT_FORKNUM)
{
- /* Never exclude init forks */
- if (relForkNum != INIT_FORKNUM)
- {
- char initForkFile[MAXPGPATH];
+ char initForkFile[MAXPGPATH];
- /*
- * If any other type of fork, check if there is an init fork
- * with the same RelFileNumber. If so, the file can be
- * excluded.
- */
- snprintf(initForkFile, sizeof(initForkFile), "%s/%u_init",
- path, relNumber);
+ /*
+ * If any other type of fork, check if there is an init fork with
+ * the same RelFileNumber. If so, the file can be excluded.
+ */
+ snprintf(initForkFile, sizeof(initForkFile), "%s/%u_init",
+ path, relfilenumber);
- if (lstat(initForkFile, &statbuf) == 0)
- {
- elog(DEBUG2,
- "unlogged relation file \"%s\" excluded from backup",
- de->d_name);
+ if (lstat(initForkFile, &statbuf) == 0)
+ {
+ elog(DEBUG2,
+ "unlogged relation file \"%s\" excluded from backup",
+ de->d_name);
- continue;
- }
+ continue;
}
}
/* Exclude temporary relations */
- if (isDbDir && looks_like_temp_rel_name(de->d_name))
+ if (OidIsValid(dboid) && looks_like_temp_rel_name(de->d_name))
{
elog(DEBUG2,
"temporary relation file \"%s\" excluded from backup",
if (!sizeonly)
sent = sendFile(sink, pathbuf, pathbuf + basepathlen + 1, &statbuf,
- true, isDbDir ? atooid(lastDir + 1) : InvalidOid, spcoid,
- manifest);
+ true, dboid, spcoid,
+ relfilenumber, segno, manifest);
if (sent || sizeonly)
{
return size;
}
-/*
- * Check if a file should have its checksum validated.
- * We validate checksums on files in regular tablespaces
- * (including global and default) only, and in those there
- * are some files that are explicitly excluded.
- */
-static bool
-is_checksummed_file(const char *fullpath, const char *filename)
-{
- /* Check that the file is in a tablespace */
- if (strncmp(fullpath, "./global/", 9) == 0 ||
- strncmp(fullpath, "./base/", 7) == 0 ||
- strncmp(fullpath, "/", 1) == 0)
- {
- int excludeIdx;
-
- /* Compare file against noChecksumFiles skip list */
- for (excludeIdx = 0; noChecksumFiles[excludeIdx].name != NULL; excludeIdx++)
- {
- int cmplen = strlen(noChecksumFiles[excludeIdx].name);
-
- if (!noChecksumFiles[excludeIdx].match_prefix)
- cmplen++;
- if (strncmp(filename, noChecksumFiles[excludeIdx].name,
- cmplen) == 0)
- return false;
- }
-
- return true;
- }
- else
- return false;
-}
-
/*
* Given the member, write the TAR header & send the file.
*
static bool
sendFile(bbsink *sink, const char *readfilename, const char *tarfilename,
struct stat *statbuf, bool missing_ok, Oid dboid, Oid spcoid,
+ RelFileNumber relfilenumber, unsigned segno,
backup_manifest_info *manifest)
{
int fd;
int checksum_failures = 0;
off_t cnt;
pgoff_t bytes_done = 0;
- int segmentno = 0;
- char *segmentpath;
bool verify_checksum = false;
pg_checksum_context checksum_ctx;
*/
Assert((sink->bbs_buffer_length % BLCKSZ) == 0);
- if (!noverify_checksums && DataChecksumsEnabled())
- {
- char *filename;
-
- /*
- * Get the filename (excluding path). As last_dir_separator()
- * includes the last directory separator, we chop that off by
- * incrementing the pointer.
- */
- filename = last_dir_separator(readfilename) + 1;
-
- if (is_checksummed_file(readfilename, filename))
- {
- verify_checksum = true;
-
- /*
- * Cut off at the segment boundary (".") to get the segment number
- * in order to mix it into the checksum.
- */
- segmentpath = strstr(filename, ".");
- if (segmentpath != NULL)
- {
- segmentno = atoi(segmentpath + 1);
- if (segmentno == 0)
- ereport(ERROR,
- (errmsg("invalid segment number %d in file \"%s\"",
- segmentno, filename)));
- }
- }
- }
+ /*
+ * If we weren't told not to verify checksums, and if checksums are
+ * enabled for this cluster, and if this is a relation file, then verify
+ * the checksum.
+ */
+ if (!noverify_checksums && DataChecksumsEnabled() &&
+ RelFileNumberIsValid(relfilenumber))
+ verify_checksum = true;
/*
* Loop until we read the amount of data the caller told us to expect. The
/* Try to read some more data. */
cnt = read_file_data_into_buffer(sink, readfilename, fd, bytes_done,
remaining,
- blkno + segmentno * RELSEG_SIZE,
+ blkno + segno * RELSEG_SIZE,
verify_checksum,
&checksum_failures);