pg_fatal("%s: manifest system identifier is %" PRIu64 ", but control file has %" PRIu64,
controlpath,
manifests[i]->system_identifier,
system_identifier);
}
}
/* Figure out which tablespaces are going to be included in the output. */
last_input_dir = argv[argc - 1];
check_input_dir_permissions(last_input_dir);
tablespaces = scan_for_existing_tablespaces(last_input_dir, &opt);
/* If we need to write a backup_manifest, prepare to do so. */ if (!opt.dry_run && !opt.no_manifest)
{
mwriter = create_manifest_writer(opt.output, system_identifier);
/* *Verifythatwehaveabackupmanifestforthefinalbackup;elsewe *won'thavetheWALrangesfortheresultingmanifest.
*/ if (manifests[n_prior_backups] == NULL)
pg_fatal("cannot generate a manifest because no manifest is available for the final input backup");
} else
mwriter = NULL;
/* Process everything that's not part of a user-defined tablespace. */
pg_log_debug("processing backup directory \"%s\"", last_input_dir);
process_directory_recursively(InvalidOid, last_input_dir, opt.output,
NULL, n_prior_backups, prior_backup_dirs,
manifests, mwriter, &opt);
if (opt.dry_run)
pg_log_debug("would create symbolic link from \"%s\" to \"%s\"",
linkpath, ts->new_dir); else
{
pg_log_debug("creating symbolic link from \"%s\" to \"%s\"",
linkpath, ts->new_dir); if (symlink(ts->new_dir, linkpath) != 0)
pg_fatal("could not create symbolic link from \"%s\" to \"%s\": %m",
linkpath, ts->new_dir);
}
} else
{ if (opt.dry_run)
pg_log_debug("would create directory \"%s\"", ts->new_dir); else
{
pg_log_debug("creating directory \"%s\"", ts->new_dir); if (pg_mkdir_p(ts->new_dir, pg_dir_create_mode) == -1)
pg_fatal("could not create directory \"%s\": %m",
ts->new_dir);
}
}
/* OK, now handle the directory contents. */
process_directory_recursively(ts->oid, ts->old_dir, ts->new_dir,
NULL, n_prior_backups, prior_backup_dirs,
manifests, mwriter, &opt);
}
/* Finalize the backup_manifest, if we're generating one. */ if (mwriter != NULL)
finalize_manifest(mwriter,
manifests[n_prior_backups]->first_wal_range);
/* fsync that output directory unless we've been told not to do so */ if (!opt.no_sync)
{ if (opt.dry_run)
pg_log_debug("would recursively fsync \"%s\"", opt.output); else
{
pg_log_debug("recursively fsyncing \"%s\"", opt.output);
sync_pgdata(opt.output, version, opt.sync_method, true);
}
}
/* Warn about the possibility of compromising the backups, when link mode */ if (opt.copy_method == COPY_METHOD_LINK)
pg_log_warning("--link mode was used; any modifications to the output " "directory might destructively modify input directories");
/* It's a success, so don't remove the output directories. */
reset_directory_cleanup_list(); exit(0);
}
/* *Basically,wejustwanttocopyeverythingbeforetheequalssignto *tsmap->old_dirandeverythingafterwardstotsmap->new_dir,butif *there'smoreorlessthanoneequalssign,that'sanerror,andif *there'sanequalssignprecededbyabackslash,don'ttreatitasa *fieldseparatorbutinsteadcopyaliteralequalssign.
*/
dst_ptr = dst = tsmap->old_dir; for (arg_ptr = arg; *arg_ptr != '\0'; arg_ptr++)
{ if (dst_ptr - dst >= MAXPGPATH)
pg_fatal("directory name too long");
if (*arg_ptr == '\\' && *(arg_ptr + 1) == '=')
; /* skip backslash escaping = */ elseif (*arg_ptr == '=' && (arg_ptr == arg || *(arg_ptr - 1) != '\\'))
{ if (tsmap->new_dir[0] != '\0')
pg_fatal("multiple \"=\" signs in tablespace mapping"); else
dst = dst_ptr = tsmap->new_dir;
} else
*dst_ptr++ = *arg_ptr;
} if (!tsmap->old_dir[0] || !tsmap->new_dir[0])
pg_fatal("invalid tablespace mapping format \"%s\", must be \"OLDDIR=NEWDIR\"", arg);
/* *Alltablespacesarecreatedwithabsolutedirectories,sospecifyinga *non-absolutepathherewouldnevermatch,possiblyconfusingusers. * *Incontrasttopg_basebackup,boththeoldandnewdirectoriesareon *thelocalmachine,sothelocalmachine'sdefinitionofanabsolute *pathistheonlyrelevantone.
*/ if (!is_absolute_path(tsmap->old_dir))
pg_fatal("old directory is not an absolute path in tablespace mapping: %s",
tsmap->old_dir);
if (!is_absolute_path(tsmap->new_dir))
pg_fatal("new directory is not an absolute path in tablespace mapping: %s",
tsmap->new_dir);
/* Canonicalize paths to avoid spurious failures when comparing. */
canonicalize_path(tsmap->old_dir);
canonicalize_path(tsmap->new_dir);
/* Add it to the list. */
tsmap->next = opt->tsmappings;
opt->tsmappings = tsmap;
}
/* Try to read each backup_label file in turn, last to first. */ for (i = n_backups - 1; i >= 0; --i)
{ char pathbuf[MAXPGPATH]; int fd;
TimeLineID start_tli;
TimeLineID previous_tli;
XLogRecPtr start_lsn;
XLogRecPtr previous_lsn;
/* Open the backup_label file. */
snprintf(pathbuf, MAXPGPATH, "%s/backup_label", backup_dirs[i]);
pg_log_debug("reading \"%s\"", pathbuf); if ((fd = open(pathbuf, O_RDONLY, 0)) < 0)
pg_fatal("could not open file \"%s\": %m", pathbuf);
/* *Sanitychecks. * *XXX.It'sactuallynotrequiredthatstart_lsn==check_lsn.It *wouldbeOKifstart_lsn>check_lsnprovidedthatstart_lsnis *lessthanorequaltotherelevantswitchpoint.Butatthemoment *wedon'thavethatinformation.
*/ if (i > 0 && previous_tli == 0)
pg_fatal("backup at \"%s\" is a full backup, but only the first backup should be a full backup",
backup_dirs[i]); if (i == 0 && previous_tli != 0)
pg_fatal("backup at \"%s\" is an incremental backup, but the first backup should be a full backup",
backup_dirs[i]); if (i < n_backups - 1 && start_tli != check_tli)
pg_fatal("backup at \"%s\" starts on timeline %u, but expected %u",
backup_dirs[i], start_tli, check_tli); if (i < n_backups - 1 && start_lsn != check_lsn)
pg_fatal("backup at \"%s\" starts at LSN %X/%X, but expected %X/%X",
backup_dirs[i],
LSN_FORMAT_ARGS(start_lsn),
LSN_FORMAT_ARGS(check_lsn));
check_tli = previous_tli;
check_lsn = previous_lsn;
/* Try to read each control file in turn, last to first. */ for (i = n_backups - 1; i >= 0; --i)
{
ControlFileData *control_file; bool crc_ok; char *controlpath;
/* Control file contents not meaningful if CRC is bad. */ if (!crc_ok)
pg_fatal("%s: CRC is incorrect", controlpath);
/* Can't interpret control file if not current version. */ if (control_file->pg_control_version != PG_CONTROL_VERSION)
pg_fatal("%s: unexpected control file version",
controlpath);
/* System identifiers should all match. */ if (i == n_backups - 1)
system_identifier = control_file->system_identifier; elseif (system_identifier != control_file->system_identifier)
pg_fatal("%s: expected system identifier %" PRIu64 ", but found %" PRIu64,
controlpath, system_identifier,
control_file->system_identifier);
/* *Ifdebugoutputisenabled,makeanoteofthesystemidentifierthat *wefoundinalloftherelevantcontrolfiles.
*/
pg_log_debug("system identifier is %" PRIu64, system_identifier);
/* *Warntheuserifnotallbackupsareinthesamestatewithregardsto *checksums.
*/ if (data_checksum_mismatch)
{
pg_log_warning("only some backups have checksums enabled");
pg_log_warning_hint("Disable, and optionally reenable, checksums on the output directory to avoid failures.");
}
case2: case3: case4:
pg_fatal("directory \"%s\" exists but is not empty", dirname);
case -1:
pg_fatal("could not access directory \"%s\": %m", dirname);
}
}
/* *help * *Printshelppagefortheprogram * *progname:thenameoftheexecutedprogram,suchas"pg_combinebackup"
*/ staticvoid
help(constchar *progname)
{
printf(_("%s reconstructs full backups from incrementals.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s [OPTION]... DIRECTORY...\n"), progname);
printf(_("\nOptions:\n"));
printf(_(" -d, --debug generate lots of debugging output\n"));
printf(_(" -k, --link link files instead of copying\n"));
printf(_(" -n, --dry-run do not actually do anything\n"));
printf(_(" -N, --no-sync do not wait for changes to be written safely to disk\n"));
printf(_(" -o, --output=DIRECTORY output directory\n"));
printf(_(" -T, --tablespace-mapping=OLDDIR=NEWDIR\n" " relocate tablespace in OLDDIR to NEWDIR\n"));
printf(_(" --clone clone (reflink) files instead of copying\n"));
printf(_(" --copy copy files (default)\n"));
printf(_(" --copy-file-range copy using copy_file_range() system call\n"));
printf(_(" --manifest-checksums=SHA{224,256,384,512}|CRC32C|NONE\n" " use algorithm for manifest checksums\n"));
printf(_(" --no-manifest suppress generation of backup manifest\n"));
printf(_(" --sync-method=METHOD set method for syncing files to disk\n"));
printf(_(" -V, --version output version information, then exit\n"));
printf(_(" -?, --help show this help, then exit\n"));
printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
}
/* *Trytoparseastringasanon-zeroOIDwithoutleadingzeroes. * *Ifitworks,returntrueandset*resulttotheanswer,elsereturnfalse.
*/ staticbool
parse_oid(char *s, Oid *result)
{
Oid oid; char *ep;
errno = 0;
oid = strtoul(s, &ep, 10); if (errno != 0 || *ep != '\0' || oid < 1 || oid > PG_UINT32_MAX) returnfalse;
/* *Topleveloutputdirectorieshavealreadybeencreatedbythetimethis *functioniscalled,butanysubdirectoriesareourresponsibility.
*/ if (relative_path != NULL)
{ if (opt->dry_run)
pg_log_debug("would create directory \"%s\"", ofulldir); else
{
pg_log_debug("creating directory \"%s\"", ofulldir); if (mkdir(ofulldir, pg_dir_create_mode) == -1)
pg_fatal("could not create directory \"%s\": %m", ofulldir);
}
}
/* It's time to scan the directory. */ if ((dir = opendir(ifulldir)) == NULL)
pg_fatal("could not open directory \"%s\": %m", ifulldir); while (errno = 0, (de = readdir(dir)) != NULL)
{
PGFileType type; char ifullpath[MAXPGPATH]; char ofullpath[MAXPGPATH]; char manifest_path[MAXPGPATH];
Oid oid = InvalidOid; int checksum_length = 0;
uint8 *checksum_payload = NULL;
pg_checksum_context checksum_ctx;
/* Ignore "." and ".." entries. */ if (strcmp(de->d_name, ".") == 0 ||
strcmp(de->d_name, "..") == 0) continue;
/* Figure out what kind of directory entry this is. */
type = get_dirent_type(ifullpath, de, false, PG_LOG_ERROR); if (type == PGFILETYPE_ERROR) exit(1);
/* Open file. */ if ((fd = open(filename, O_RDONLY, 0)) < 0)
pg_fatal("could not open file \"%s\": %m", filename);
/* Read into memory. Length limit of 128 should be more than generous. */
initStringInfo(&buf);
slurp_file(fd, filename, &buf, 128);
/* Close the file. */ if (close(fd) != 0)
pg_fatal("could not close file \"%s\": %m", filename);
/* Convert to integer. */
errno = 0;
version = strtoul(buf.data, &ep, 10); if (errno != 0 || *ep != '\n')
{ /* *Incrementalbackupisnotrelevanttoveryoldserverversionsthat *usedmulti-partversionnumber(e.g.9.6,or8.4).Soifwesee *whatlookslikethebeginningofsuchaversionnumber,justbail *out.
*/ if (version < 10 && *ep == '.')
pg_fatal("%s: server version too old", filename);
pg_fatal("%s: could not parse version number", filename);
}
/* Debugging output. */
pg_log_debug("read server version %d from file \"%s\"", version, filename);
/* Release memory and return result. */
pfree(buf.data); return version * 10000;
}
if ((dir = opendir(pg_tblspc)) == NULL)
pg_fatal("could not open directory \"%s\": %m", pg_tblspc);
while (errno = 0, (de = readdir(dir)) != NULL)
{
Oid oid; char tblspcdir[MAXPGPATH]; char link_target[MAXPGPATH]; int link_length;
cb_tablespace *ts;
cb_tablespace *otherts;
PGFileType type;
/* Silently ignore "." and ".." entries. */ if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;
/* Construct full pathname. */
snprintf(tblspcdir, MAXPGPATH, "%s/%s", pg_tblspc, de->d_name);
/* Ignore any file name that doesn't look like a proper OID. */ if (!parse_oid(de->d_name, &oid))
{
pg_log_debug("skipping \"%s\" because the filename is not a legal tablespace OID",
tblspcdir); continue;
}
/* Only symbolic links and directories are tablespaces. */
type = get_dirent_type(tblspcdir, de, false, PG_LOG_ERROR); if (type == PGFILETYPE_ERROR) exit(1); if (type != PGFILETYPE_LNK && type != PGFILETYPE_DIR)
{
pg_log_debug("skipping \"%s\" because it is neither a symbolic link nor a directory",
tblspcdir); continue;
}
/* Create a new tablespace object. */
ts = pg_malloc0(sizeof(cb_tablespace));
ts->oid = oid;
/* Read the link target. */
link_length = readlink(tblspcdir, link_target, sizeof(link_target)); if (link_length < 0)
pg_fatal("could not read symbolic link \"%s\": %m",
tblspcdir); if (link_length >= sizeof(link_target))
pg_fatal("target of symbolic link \"%s\" is too long", tblspcdir);
link_target[link_length] = '\0'; if (!is_absolute_path(link_target))
pg_fatal("target of symbolic link \"%s\" is relative", tblspcdir);
/* Canonicalize the link target. */
canonicalize_path(link_target);
/* Every non-in-place tablespace must be mapped. */ if (tsmap == NULL)
pg_fatal("tablespace at \"%s\" has no tablespace mapping",
link_target);
} else
{ /* *Foranin-placetablespace,there'snoseparatedirectory,so *wejustrecordthepathswithinthedatadirectories.
*/
snprintf(ts->old_dir, MAXPGPATH, "%s/%s", pg_tblspc, de->d_name);
snprintf(ts->new_dir, MAXPGPATH, "%s/%s/%s", opt->output,
PG_TBLSPC_DIR, de->d_name);
ts->in_place = true;
}
/* Tablespaces should not share a directory. */ for (otherts = tslist; otherts != NULL; otherts = otherts->next) if (strcmp(ts->new_dir, otherts->new_dir) == 0)
pg_fatal("tablespaces with OIDs %u and %u both point at directory \"%s\"",
otherts->oid, oid, ts->new_dir);
/* Add this tablespace to the list. */
ts->next = tslist;
tslist = ts;
}
if (closedir(dir) != 0)
pg_fatal("could not close directory \"%s\": %m", pg_tblspc);
/* Check file size, and complain if it's too large. */ if (fstat(fd, &st) != 0)
pg_fatal("could not stat file \"%s\": %m", filename); if (st.st_size > maxlen)
pg_fatal("file \"%s\" is too large", filename);
/* Make sure we have enough space. */
enlargeStringInfo(buf, st.st_size);
/* Read the data. */
rb = read(fd, &buf->data[buf->len], st.st_size);
/* *Wedon'texpectanyconcurrentchanges,soweshouldreadexactlythe *expectednumberofbytes.
*/ if (rb != st.st_size)
{ if (rb < 0)
pg_fatal("could not read file \"%s\": %m", filename); else
pg_fatal("could not read file \"%s\": read %zd of %lld",
filename, rb, (longlongint) st.st_size);
}
/* Adjust buffer length for new data and restore trailing-\0 invariant */
buf->len += rb;
buf->data[buf->len] = '\0';
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-08-07)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.