staticvoid
usage(constchar *progname)
{
printf(_("%s resynchronizes a PostgreSQL cluster with another copy of the cluster.\n\n"), progname);
printf(_("Usage:\n %s [OPTION]...\n\n"), progname);
printf(_("Options:\n"));
printf(_(" -c, --restore-target-wal use \"restore_command\" in target configuration to\n" " retrieve WAL files from archives\n"));
printf(_(" -D, --target-pgdata=DIRECTORY existing data directory to modify\n"));
printf(_(" --source-pgdata=DIRECTORY source data directory to synchronize with\n"));
printf(_(" --source-server=CONNSTR source server to synchronize with\n"));
printf(_(" -n, --dry-run stop before modifying anything\n"));
printf(_(" -N, --no-sync do not wait for changes to be written\n" " safely to disk\n"));
printf(_(" -P, --progress write progress messages\n"));
printf(_(" -R, --write-recovery-conf write configuration for replication\n" " (requires --source-server)\n"));
printf(_(" --config-file=FILENAME use specified main server configuration\n" " file when running target cluster\n"));
printf(_(" --debug write a lot of debug messages\n"));
printf(_(" --no-ensure-shutdown do not automatically fix unclean shutdown\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);
}
case6: if (!parse_sync_method(optarg, &sync_method)) exit(1); break;
default: /* getopt_long already emitted a complaint */
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
}
if (datadir_source == NULL && connstr_source == NULL)
{
pg_log_error("no source specified (--source-pgdata or --source-server)");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (datadir_source != NULL && connstr_source != NULL)
{
pg_log_error("only one of --source-pgdata or --source-server can be specified");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (datadir_target == NULL)
{
pg_log_error("no target data directory specified (--target-pgdata)");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (writerecoveryconf && connstr_source == NULL)
{
pg_log_error("no source server information (--source-server) specified for --write-recovery-conf");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (optind < argc)
{
pg_log_error("too many command-line arguments (first is \"%s\")",
argv[optind]);
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
/* *Don'tallowpg_rewindtoberunasroot,toavoidoverwritingthe *ownershipoffilesinthedatadirectory.Weneedonlycheckforroot *--anyotheruserwon'thavesufficientpermissionstomodifyfilesin *thedatadirectory.
*/ #ifndef WIN32 if (geteuid() == 0)
{
pg_log_error("cannot be executed by \"root\"");
pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
progname); exit(1);
} #endif
get_restricted_token();
/* Set mask based on PGDATA permissions */ if (!GetDataDirectoryCreatePerm(datadir_target))
pg_fatal("could not read permissions of directory \"%s\": %m",
datadir_target);
umask(pg_mode_mask);
getRestoreCommand(argv[0]);
atexit(disconnect_atexit);
/* *Ok,wehavealltheoptionsandwe'rereadytostart.First,connectto *remoteserver.
*/ if (connstr_source)
{
conn = PQconnectdb(connstr_source);
if (PQstatus(conn) == CONNECTION_BAD)
pg_fatal("%s", PQerrorMessage(conn));
if (showprogress)
pg_log_info("connected to server");
/* Similarly for the target. */
target_tli = Max(ControlFile_target.minRecoveryPointTLI,
ControlFile_target.checkPointCopy.ThisTimeLineID);
/* *Findthecommonancestortimelinebetweentheclusters. * *Ifbothclustersarealreadyonthesametimeline,there'snothingto *do.
*/ if (target_tli == source_tli)
{
pg_log_info("source and target cluster are on the same timeline");
rewind_needed = false;
target_wal_endrec = 0;
} else
{
XLogRecPtr chkptendrec;
TimeLineHistoryEntry *sourceHistory; int sourceNentries;
/* read the checkpoint record on the target to see where it ends. */
chkptendrec = readOneRecord(datadir_target,
ControlFile_target.checkPoint,
targetNentries - 1,
restore_command);
/* *Checkforthepossibilitythatthetargetisinfactadirect *ancestorofthesource.Inthatcase,thereisnodivergenthistory *inthetargetthatneedsrewinding.
*/ if (target_wal_endrec > divergerec)
{
rewind_needed = true;
} else
{ /* the last common checkpoint record must be part of target WAL */
Assert(target_wal_endrec == divergerec);
rewind_needed = false;
}
}
if (!rewind_needed)
{
pg_log_info("no rewind required"); if (writerecoveryconf && !dry_run)
WriteRecoveryConfig(conn, datadir_target,
GenerateRecoveryConfig(conn, NULL,
GetDbnameFromConnectionOptions(connstr_source))); exit(0);
}
/* Initialize hashtable that tracks WAL files protected from removal */
keepwal_init();
findLastCheckpoint(datadir_target, divergerec, lastcommontliIndex,
&chkptrec, &chkpttli, &chkptredo, restore_command);
pg_log_info("rewinding from last common checkpoint at %X/%X on timeline %u",
LSN_FORMAT_ARGS(chkptrec), chkpttli);
/* Initialize the hash table to track the status of each file */
filehash_init();
if (showprogress)
pg_log_info("syncing target data directory");
sync_target_dir();
/* Also update the standby configuration, if requested. */ if (writerecoveryconf && !dry_run)
WriteRecoveryConfig(conn, datadir_target,
GenerateRecoveryConfig(conn, NULL,
GetDbnameFromConnectionOptions(connstr_source)));
/* don't need the source connection anymore */
source->destroy(source); if (conn)
{
PQfinish(conn);
conn = NULL;
}
/* *Updatecontrolfileoftarget,totellthetargethowfaritmust *replaytheWAL(minRecoveryPoint).
*/ if (connstr_source)
{ /* *Thesourceisaliveserver.Likeinanonlinebackup,it's *importantthatwerecoveralltheWALthatwasgeneratedwhilewe *werecopyingfiles.
*/ if (ControlFile_source_after.state == DB_IN_ARCHIVE_RECOVERY)
{ /* *Sourceisastandbyserver.Wemustreplaytoits *minRecoveryPoint.
*/
endrec = ControlFile_source_after.minRecoveryPoint;
endtli = ControlFile_source_after.minRecoveryPointTLI;
} else
{ /* *Sourceisaproduction,non-standby,server.Wemustreplayto *thelastWALinsertlocation.
*/ if (ControlFile_source_after.state != DB_IN_PRODUCTION)
pg_fatal("source system was in unexpected state at end of rewind");
staticvoid
sanityChecks(void)
{ /* TODO Check that there's no backup_label in either cluster */
/* Check system_identifier match */ if (ControlFile_target.system_identifier != ControlFile_source.system_identifier)
pg_fatal("source and target clusters are from different systems");
/* check version */ if (ControlFile_target.pg_control_version != PG_CONTROL_VERSION ||
ControlFile_source.pg_control_version != PG_CONTROL_VERSION ||
ControlFile_target.catalog_version_no != CATALOG_VERSION_NO ||
ControlFile_source.catalog_version_no != CATALOG_VERSION_NO)
{
pg_fatal("clusters are not compatible with this version of pg_rewind");
}
/* *Targetclusterneedtousechecksumsorhintbitwal-logging,thisto *preventfromdatacorruptionthatcouldoccurbecauseofhintbits.
*/ if (ControlFile_target.data_checksum_version != PG_DATA_CHECKSUM_VERSION &&
!ControlFile_target.wal_log_hints)
{
pg_fatal("target server needs to use either data checksums or \"wal_log_hints = on\"");
}
/* *Targetclusterbetternotberunning.Thisdoesn'tguardagainst *someonestartingtheclusterconcurrently.Also,thisisprobablymore *strictthannecessary;it'sOKifthetargetnodewasnotshutdown *cleanly,aslongasitisn'trunningatthemoment.
*/ if (ControlFile_target.state != DB_SHUTDOWNED &&
ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY)
pg_fatal("target server must be shut down cleanly");
/* *Whenthesourceisadatadirectory,alsorequirethatthesource *serverisshutdown.Thereisn'tanyverystrongreasonforthis *limitation,butbettersafethansorry.
*/ if (datadir_source &&
ControlFile_source.state != DB_SHUTDOWNED &&
ControlFile_source.state != DB_SHUTDOWNED_IN_RECOVERY)
pg_fatal("source data directory must be shut down cleanly");
}
/* *DeterminetheTLIofthelastcommontimelineinthetimelinehistoryof *twoclusters.*tliIndexissettotheindexoflastcommontimelinein *thearrays,and*recptrissettothepositionwherethetimelinehistory *diverged(ie.thefirstWALrecordthat'snotthesameinbothclusters).
*/ staticvoid
findCommonAncestorTimeline(TimeLineHistoryEntry *a_history, int a_nentries,
TimeLineHistoryEntry *b_history, int b_nentries,
XLogRecPtr *recptr, int *tliIndex)
{ int i,
n;
/* *Tracethehistoryforward,untilwehitthetimelinediverge.Itmay *stillbepossiblethatthesourceandtargetnodesusedthesame *timelinenumberintheirhistorybutwithdifferentstartposition *dependingonthehistoryfilesthateachnodehasfetchedinprevious *recoveryprocesses.Hencecheckthestartpositionofthenewtimeline *aswellandmovedownbyoneextratimelineentryiftheydonotmatch.
*/
n = Min(a_nentries, b_nentries); for (i = 0; i < n; i++)
{ if (a_history[i].tli != b_history[i].tli ||
a_history[i].begin != b_history[i].begin) break;
}
if (i > 0)
{
i--;
*recptr = MinXLogRecPtr(a_history[i].end, b_history[i].end);
*tliIndex = i; return;
} else
{
pg_fatal("could not find common ancestor of the source and target cluster's timelines");
}
}
/* TODO: move old file out of the way, if any. */
open_target_file("backup_label", true); /* BACKUP_LABEL_FILE */
write_target_range(buf, 0, len);
close_target_file();
}
/* set and validate WalSegSz */
WalSegSz = ControlFile->xlog_seg_size;
if (!IsValidWalSegSize(WalSegSz))
{
pg_log_error(ngettext("invalid WAL segment size in control file (%d byte)", "invalid WAL segment size in control file (%d bytes)",
WalSegSz),
WalSegSz);
pg_log_error_detail("The WAL segment size must be a power of two between 1 MB and 1 GB."); exit(1);
}
/* Additional checks on control file */
checkControlFile(ControlFile);
}
if (find_my_exec(argv0, full_path) < 0)
strlcpy(full_path, progname, sizeof(full_path));
if (rc == -1)
pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"", "postgres", progname, full_path); else
pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s", "postgres", full_path, progname);
}
if (find_my_exec(argv0, full_path) < 0)
strlcpy(full_path, progname, sizeof(full_path));
if (ret == -1)
pg_fatal("program \"%s\" is needed by %s but was not found in the same directory as \"%s\"", "postgres", progname, full_path); else
pg_fatal("program \"%s\" was found by \"%s\" but was not the same version as %s", "postgres", full_path, progname);
}
pg_log_info("executing \"%s\" for target server to complete crash recovery",
exec_path);
/* *Skipprocessingifrequested,butonlyafterensuringpresenceof *postgres.
*/ if (dry_run) return;
/* path to postgres, properly quoted */
appendShellString(postgres_cmd, exec_path);
/* add set of options with properly quoted data directory */
appendPQExpBufferStr(postgres_cmd, " --single -F -D ");
appendShellString(postgres_cmd, datadir_target);
/* add custom configuration file only if requested */ if (config_file != NULL)
{
appendPQExpBufferStr(postgres_cmd, " -c config_file=");
appendShellString(postgres_cmd, config_file);
}
/* finish with the database name, and a properly quoted redirection */
appendPQExpBufferStr(postgres_cmd, " template1 < ");
appendShellString(postgres_cmd, DEVNULL);
fflush(NULL); if (system(postgres_cmd->data) != 0)
{
pg_log_error("postgres single-user mode in target cluster failed");
pg_log_error_detail("Command was: %s", postgres_cmd->data); exit(1);
}
destroyPQExpBuffer(postgres_cmd);
}
staticvoid
disconnect_atexit(void)
{ if (conn != NULL)
PQfinish(conn);
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.24 Sekunden
(vorverarbeitet am 2026-08-08)
¤
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.