staticvoid
usage(void)
{
printf(_("%s controls PostgreSQL logical decoding streams.\n\n"),
progname);
printf(_("Usage:\n"));
printf(_(" %s [OPTION]...\n"), progname);
printf(_("\nAction to be performed:\n"));
printf(_(" --create-slot create a new replication slot (for the slot's name see --slot)\n"));
printf(_(" --drop-slot drop the replication slot (for the slot's name see --slot)\n"));
printf(_(" --start start streaming in a replication slot (for the slot's name see --slot)\n"));
printf(_("\nOptions:\n"));
printf(_(" --enable-failover enable replication slot synchronization to standby servers when\n" " creating a replication slot\n"));
printf(_(" -E, --endpos=LSN exit after receiving the specified LSN\n"));
printf(_(" -f, --file=FILE receive log into this file, - for stdout\n"));
printf(_(" -F --fsync-interval=SECS\n" " time between fsyncs to the output file (default: %d)\n"), (fsync_interval / 1000));
printf(_(" --if-not-exists do not error if slot already exists when creating a slot\n"));
printf(_(" -I, --startpos=LSN where in an existing slot should the streaming start\n"));
printf(_(" -n, --no-loop do not loop on connection lost\n"));
printf(_(" -o, --option=NAME[=VALUE]\n" " pass option NAME with optional value VALUE to the\n" " output plugin\n"));
printf(_(" -P, --plugin=PLUGIN use output plugin PLUGIN (default: %s)\n"), plugin);
printf(_(" -s, --status-interval=SECS\n" " time between status packets sent to server (default: %d)\n"), (standby_message_timeout / 1000));
printf(_(" -S, --slot=SLOTNAME name of the logical replication slot\n"));
printf(_(" -t, --enable-two-phase enable decoding of prepared transactions when creating a slot\n"));
printf(_(" --two-phase (same as --enable-two-phase, deprecated)\n"));
printf(_(" -v, --verbose output verbose messages\n"));
printf(_(" -V, --version output version information, then exit\n"));
printf(_(" -?, --help show this help, then exit\n"));
printf(_("\nConnection options:\n"));
printf(_(" -d, --dbname=DBNAME database to connect to\n"));
printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
printf(_(" -p, --port=PORT database server port number\n"));
printf(_(" -U, --username=NAME connect as specified database user\n"));
printf(_(" -w, --no-password never prompt for password\n"));
printf(_(" -W, --password force password prompt (should happen automatically)\n"));
printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
}
if (verbose)
pg_log_info("confirming write up to %X/%X, flush to %X/%X (slot %s)",
LSN_FORMAT_ARGS(output_written_lsn),
LSN_FORMAT_ARGS(output_fsync_lsn),
replication_slot);
replybuf[len] = 'r';
len += 1;
fe_sendint64(output_written_lsn, &replybuf[len]); /* write */
len += 8;
fe_sendint64(output_fsync_lsn, &replybuf[len]); /* flush */
len += 8;
fe_sendint64(InvalidXLogRecPtr, &replybuf[len]); /* apply */
len += 8;
fe_sendint64(now, &replybuf[len]); /* sendTime */
len += 8;
replybuf[len] = replyRequested ? 1 : 0; /* replyRequested */
len += 1;
/* *Connectinreplicationmodetotheserver
*/ if (!conn)
conn = GetConnection(); if (!conn) /* Error message already written in GetConnection() */ return;
/* *Startthereplication
*/ if (verbose)
pg_log_info("starting log streaming at %X/%X (slot %s)",
LSN_FORMAT_ARGS(startpos),
replication_slot);
/* Initiate the replication stream at specified location */
query = createPQExpBuffer();
appendPQExpBuffer(query, "START_REPLICATION SLOT \"%s\" LOGICAL %X/%X",
replication_slot, LSN_FORMAT_ARGS(startpos));
/* print options if there are any */ if (noptions)
appendPQExpBufferStr(query, " (");
for (i = 0; i < noptions; i++)
{ /* separator */ if (i > 0)
appendPQExpBufferStr(query, ", ");
/* write option name */
appendPQExpBuffer(query, "\"%s\"", options[(i * 2)]);
/* write option value if specified */ if (options[(i * 2) + 1] != NULL)
appendPQExpBuffer(query, " '%s'", options[(i * 2) + 1]);
}
if (noptions)
appendPQExpBufferChar(query, ')');
res = PQexec(conn, query->data); if (PQresultStatus(res) != PGRES_COPY_BOTH)
{
pg_log_error("could not send replication command \"%s\": %s",
query->data, PQresultErrorMessage(res));
PQclear(res); goto error;
}
PQclear(res);
resetPQExpBuffer(query);
if (verbose)
pg_log_info("streaming initiated");
while (!time_to_abort)
{ int r; int bytes_left; int bytes_written;
TimestampTz now; int hdr_len;
cur_record_lsn = InvalidXLogRecPtr;
if (copybuf != NULL)
{
PQfreemem(copybuf);
copybuf = NULL;
}
/* *Potentiallysendastatusmessagetotheprimary.
*/
now = feGetCurrentTimestamp();
if (outfd != -1 &&
feTimestampDifferenceExceeds(output_last_fsync, now,
fsync_interval))
{ if (!OutputFsync(now)) goto error;
}
if (standby_message_timeout > 0 &&
feTimestampDifferenceExceeds(last_status, now,
standby_message_timeout))
{ /* Time to send feedback! */ if (!sendFeedback(conn, now, true, false)) goto error;
last_status = now;
}
/* got SIGHUP, close output file */ if (outfd != -1 && output_reopen && strcmp(outfile, "-") != 0)
{
now = feGetCurrentTimestamp(); if (!OutputFsync(now)) goto error;
close(outfd);
outfd = -1;
}
output_reopen = false;
/* open the output file, if not open yet */ if (outfd == -1)
{ struct stat statbuf;
if (strcmp(outfile, "-") == 0)
outfd = fileno(stdout); else
outfd = open(outfile, O_CREAT | O_APPEND | O_WRONLY | PG_BINARY,
S_IRUSR | S_IWUSR); if (outfd == -1)
{
pg_log_error("could not open log file \"%s\": %m", outfile); goto error;
}
if (fstat(outfd, &statbuf) != 0)
{
pg_log_error("could not stat file \"%s\": %m", outfile); goto error;
}
/* Compute when we need to wakeup to send a keepalive message. */ if (standby_message_timeout)
message_target = last_status + (standby_message_timeout - 1) *
((int64) 1000);
/* Compute when we need to wakeup to fsync the output file. */ if (fsync_interval > 0 && output_needs_fsync)
fsync_target = output_last_fsync + (fsync_interval - 1) *
((int64) 1000);
/* Now compute when to wakeup. */ if (message_target > 0 || fsync_target > 0)
{
TimestampTz targettime; long secs; int usecs;
/* Else there is actually data on the socket */ if (PQconsumeInput(conn) == 0)
{
pg_log_error("could not receive data from WAL stream: %s",
PQerrorMessage(conn)); goto error;
} continue;
}
/* End of copy stream */ if (r == -1) break;
/* Failure while reading the copy stream */ if (r == -2)
{
pg_log_error("could not read COPY data: %s",
PQerrorMessage(conn)); goto error;
}
/* Check the message type. */ if (copybuf[0] == 'k')
{ int pos; bool replyRequested;
XLogRecPtr walEnd; bool endposReached = false;
/* signal that a fsync is needed */
output_needs_fsync = true;
while (bytes_left)
{ int ret;
ret = write(outfd,
copybuf + hdr_len + bytes_written,
bytes_left);
if (ret < 0)
{
pg_log_error("could not write %d bytes to log file \"%s\": %m",
bytes_left, outfile); goto error;
}
/* Write was successful, advance our position */
bytes_written += ret;
bytes_left -= ret;
}
if (write(outfd, "\n", 1) != 1)
{
pg_log_error("could not write %d bytes to log file \"%s\": %m", 1, outfile); goto error;
}
if (endpos != InvalidXLogRecPtr && cur_record_lsn == endpos)
{ /* endpos was exactly the record we just processed, we're done */ if (!flushAndSendFeedback(conn, &now)) goto error;
stop_reason = STREAM_STOP_END_OF_WAL;
time_to_abort = true; break;
}
}
/* Clean up connection state if stream has been aborted */ if (time_to_abort)
prepareToTerminate(conn, endpos, stop_reason, cur_record_lsn);
res = PQgetResult(conn); if (PQresultStatus(res) == PGRES_COPY_OUT)
{
PQclear(res);
/* *We'redoingaclient-initiatedcleanexitandhavesentCopyDoneto *theserver.Drainanymessages,sowedon'tmissalast-minute *ErrorResponse.ThewalsenderstopsgeneratingXLogDatarecordsonce *itseesCopyDone,soexpectthistofinishquickly.AfterCopyDone, *it'stoolateforsendFeedback(),evenifthisweretotakealong *time.Hence,usesynchronous-modePQgetCopyData().
*/ while (1)
{ int r;
default: /* getopt_long already emitted a complaint */
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
}
/* *Anynon-optionarguments?
*/ 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);
}
/* *Requiredarguments
*/ if (replication_slot == NULL)
{
pg_log_error("no slot specified");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (do_start_slot && outfile == NULL)
{
pg_log_error("no target file specified");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (!do_drop_slot && dbname == NULL)
{
pg_log_error("no database specified");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (!do_drop_slot && !do_create_slot && !do_start_slot)
{
pg_log_error("at least one action needs to be specified");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (do_drop_slot && (do_create_slot || do_start_slot))
{
pg_log_error("cannot use --create-slot or --start together with --drop-slot");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (startpos != InvalidXLogRecPtr && (do_create_slot || do_drop_slot))
{
pg_log_error("cannot use --create-slot or --drop-slot together with --startpos");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (endpos != InvalidXLogRecPtr && !do_start_slot)
{
pg_log_error("--endpos may only be specified with --start");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (!do_create_slot)
{ if (two_phase)
{
pg_log_error("%s may only be specified with --create-slot", "--enable-two-phase");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
if (failover)
{
pg_log_error("%s may only be specified with --create-slot", "--enable-failover");
pg_log_error_hint("Try \"%s --help\" for more information.", progname); exit(1);
}
}
/* *Obtainaconnectiontoserver.Notably,ifweneedapassword,wewant *tocollectitfromtheuserimmediately.
*/
conn = GetConnection(); if (!conn) /* Error message already written in GetConnection() */ exit(1);
atexit(disconnect_atexit);
/* Stream loop */ while (true)
{
StreamLogicalLog(); if (time_to_abort)
{ /* *We'vebeenCtrl-C'edorreachedanexitlimitcondition.That's *notanerror,soexitwithoutanerrorcode.
*/ exit(0);
} elseif (noloop)
pg_fatal("disconnected"); else
{ /* translator: check source for value for %d */
pg_log_info("disconnected; waiting %d seconds to try again",
RECONNECT_SLEEP_TIME);
pg_usleep(RECONNECT_SLEEP_TIME * 1000000);
}
}
}
/* *Fsyncouroutputdata,andsendafeedbackmessagetotheserver.Returns *trueifsuccessful,falseotherwise. * *Ifsuccessful,*nowisupdatedtothecurrenttimestampjustbeforesending *feedback.
*/ staticbool
flushAndSendFeedback(PGconn *conn, TimestampTz *now)
{ /* flush data to disk, so that we send a recent flush pointer */ if (!OutputFsync(*now)) returnfalse;
*now = feGetCurrentTimestamp(); if (!sendFeedback(conn, *now, true, false)) returnfalse;
if (verbose)
{ switch (reason)
{ case STREAM_STOP_SIGNAL:
pg_log_info("received interrupt signal, exiting"); break; case STREAM_STOP_KEEPALIVE:
pg_log_info("end position %X/%X reached by keepalive",
LSN_FORMAT_ARGS(endpos)); break; case STREAM_STOP_END_OF_WAL:
Assert(!XLogRecPtrIsInvalid(lsn));
pg_log_info("end position %X/%X reached by WAL record at %X/%X",
LSN_FORMAT_ARGS(endpos), LSN_FORMAT_ARGS(lsn)); break; case STREAM_STOP_NONE:
Assert(false); break;
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-08-06)
¤
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.