Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
walsender.c File Reference
#include "postgres.h"
#include <signal.h>
#include <unistd.h>
#include "access/timeline.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog_internal.h"
#include "access/xlogreader.h"
#include "access/xlogrecovery.h"
#include "access/xlogutils.h"
#include "backup/basebackup.h"
#include "backup/basebackup_incremental.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "funcapi.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "libpq/protocol.h"
#include "miscadmin.h"
#include "nodes/replnodes.h"
#include "pgstat.h"
#include "postmaster/interrupt.h"
#include "replication/decode.h"
#include "replication/logical.h"
#include "replication/slotsync.h"
#include "replication/slot.h"
#include "replication/snapbuild.h"
#include "replication/syncrep.h"
#include "replication/walreceiver.h"
#include "replication/walsender.h"
#include "replication/walsender_private.h"
#include "storage/condition_variable.h"
#include "storage/aio_subsys.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "tcop/dest.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/pg_lsn.h"
#include "utils/pgstat_internal.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
#include "utils/timestamp.h"
Include dependency graph for walsender.c:

Go to the source code of this file.

Data Structures

struct  WalTimeSample
 
struct  LagTracker
 

Macros

#define WALSENDER_STATS_FLUSH_INTERVAL   1000
 
#define MAX_SEND_SIZE   (XLOG_BLCKSZ * 16)
 
#define LAG_TRACKER_BUFFER_SIZE   8192
 
#define READ_REPLICATION_SLOT_COLS   3
 
#define WALSND_LOGICAL_LAG_TRACK_INTERVAL_MS   1000
 
#define PG_STAT_GET_WAL_SENDERS_COLS   12
 

Typedefs

typedef void(* WalSndSendDataCallback) (void)
 

Functions

static void WalSndLastCycleHandler (SIGNAL_ARGS)
 
static void WalSndLoop (WalSndSendDataCallback send_data)
 
static void InitWalSenderSlot (void)
 
static void WalSndKill (int code, Datum arg)
 
static pg_noreturn void WalSndShutdown (void)
 
static void XLogSendPhysical (void)
 
static void XLogSendLogical (void)
 
static void WalSndDone (WalSndSendDataCallback send_data)
 
static void IdentifySystem (void)
 
static void UploadManifest (void)
 
static bool HandleUploadManifestPacket (StringInfo buf, off_t *offset, IncrementalBackupInfo *ib)
 
static void ReadReplicationSlot (ReadReplicationSlotCmd *cmd)
 
static void CreateReplicationSlot (CreateReplicationSlotCmd *cmd)
 
static void DropReplicationSlot (DropReplicationSlotCmd *cmd)
 
static void StartReplication (StartReplicationCmd *cmd)
 
static void StartLogicalReplication (StartReplicationCmd *cmd)
 
static void ProcessStandbyMessage (void)
 
static void ProcessStandbyReplyMessage (void)
 
static void ProcessStandbyHSFeedbackMessage (void)
 
static void ProcessStandbyPSRequestMessage (void)
 
static void ProcessRepliesIfAny (void)
 
static void ProcessPendingWrites (void)
 
static void WalSndKeepalive (bool requestReply, XLogRecPtr writePtr)
 
static void WalSndKeepaliveIfNecessary (void)
 
static void WalSndCheckTimeOut (void)
 
static long WalSndComputeSleeptime (TimestampTz now)
 
static void WalSndWait (uint32 socket_events, long timeout, uint32 wait_event)
 
static void WalSndPrepareWrite (LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid, bool last_write)
 
static void WalSndWriteData (LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid, bool last_write)
 
static void WalSndUpdateProgress (LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid, bool skipped_xact)
 
static XLogRecPtr WalSndWaitForWal (XLogRecPtr loc)
 
static void LagTrackerWrite (XLogRecPtr lsn, TimestampTz local_flush_time)
 
static TimeOffset LagTrackerRead (int head, XLogRecPtr lsn, TimestampTz now)
 
static bool TransactionIdInRecentPast (TransactionId xid, uint32 epoch)
 
static void WalSndSegmentOpen (XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
 
void InitWalSender (void)
 
void WalSndErrorCleanup (void)
 
static void SendTimeLineHistory (TimeLineHistoryCmd *cmd)
 
static int logical_read_xlog_page (XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *cur_page)
 
static void parseCreateReplSlotOptions (CreateReplicationSlotCmd *cmd, bool *reserve_wal, CRSSnapshotAction *snapshot_action, bool *two_phase, bool *failover)
 
static void AlterReplicationSlot (AlterReplicationSlotCmd *cmd)
 
void PhysicalWakeupLogicalWalSnd (void)
 
static bool NeedToWaitForStandbys (XLogRecPtr flushed_lsn, uint32 *wait_event)
 
static bool NeedToWaitForWal (XLogRecPtr target_lsn, XLogRecPtr flushed_lsn, uint32 *wait_event)
 
bool exec_replication_command (const char *cmd_string)
 
static void PhysicalConfirmReceivedLocation (XLogRecPtr lsn)
 
static void PhysicalReplicationSlotNewXmin (TransactionId feedbackXmin, TransactionId feedbackCatalogXmin)
 
XLogRecPtr GetStandbyFlushRecPtr (TimeLineID *tli)
 
void WalSndRqstFileReload (void)
 
void HandleWalSndInitStopping (void)
 
void WalSndSignals (void)
 
Size WalSndShmemSize (void)
 
void WalSndShmemInit (void)
 
void WalSndWakeup (bool physical, bool logical)
 
void WalSndInitStopping (void)
 
void WalSndWaitStopping (void)
 
void WalSndSetState (WalSndState state)
 
static const char * WalSndGetStateString (WalSndState state)
 
static Intervaloffset_to_interval (TimeOffset offset)
 
Datum pg_stat_get_wal_senders (PG_FUNCTION_ARGS)
 

Variables

WalSndCtlDataWalSndCtl = NULL
 
WalSndMyWalSnd = NULL
 
bool am_walsender = false
 
bool am_cascading_walsender = false
 
bool am_db_walsender = false
 
int max_wal_senders = 10
 
int wal_sender_timeout = 60 * 1000
 
bool log_replication_commands = false
 
bool wake_wal_senders = false
 
static XLogReaderStatexlogreader = NULL
 
static IncrementalBackupInfouploaded_manifest = NULL
 
static MemoryContext uploaded_manifest_mcxt = NULL
 
static TimeLineID sendTimeLine = 0
 
static TimeLineID sendTimeLineNextTLI = 0
 
static bool sendTimeLineIsHistoric = false
 
static XLogRecPtr sendTimeLineValidUpto = InvalidXLogRecPtr
 
static XLogRecPtr sentPtr = InvalidXLogRecPtr
 
static StringInfoData output_message
 
static StringInfoData reply_message
 
static StringInfoData tmpbuf
 
static TimestampTz last_processing = 0
 
static TimestampTz last_reply_timestamp = 0
 
static bool waiting_for_ping_response = false
 
static bool streamingDoneSending
 
static bool streamingDoneReceiving
 
static bool WalSndCaughtUp = false
 
static volatile sig_atomic_t got_SIGUSR2 = false
 
static volatile sig_atomic_t got_STOPPING = false
 
static volatile sig_atomic_t replication_active = false
 
static LogicalDecodingContextlogical_decoding_ctx = NULL
 
static LagTrackerlag_tracker
 

Macro Definition Documentation

◆ LAG_TRACKER_BUFFER_SIZE

#define LAG_TRACKER_BUFFER_SIZE   8192

Definition at line 226 of file walsender.c.

◆ MAX_SEND_SIZE

#define MAX_SEND_SIZE   (XLOG_BLCKSZ * 16)

Definition at line 114 of file walsender.c.

◆ PG_STAT_GET_WAL_SENDERS_COLS

#define PG_STAT_GET_WAL_SENDERS_COLS   12

◆ READ_REPLICATION_SLOT_COLS

#define READ_REPLICATION_SLOT_COLS   3

◆ WALSENDER_STATS_FLUSH_INTERVAL

#define WALSENDER_STATS_FLUSH_INTERVAL   1000

Definition at line 103 of file walsender.c.

◆ WALSND_LOGICAL_LAG_TRACK_INTERVAL_MS

#define WALSND_LOGICAL_LAG_TRACK_INTERVAL_MS   1000

Typedef Documentation

◆ WalSndSendDataCallback

typedef void(* WalSndSendDataCallback) (void)

Definition at line 244 of file walsender.c.

Function Documentation

◆ AlterReplicationSlot()

static void AlterReplicationSlot ( AlterReplicationSlotCmd cmd)
static

Definition at line 1395 of file walsender.c.

1396{
1397 bool failover_given = false;
1398 bool two_phase_given = false;
1399 bool failover;
1400 bool two_phase;
1401
1402 /* Parse options */
1403 foreach_ptr(DefElem, defel, cmd->options)
1404 {
1405 if (strcmp(defel->defname, "failover") == 0)
1406 {
1407 if (failover_given)
1408 ereport(ERROR,
1409 (errcode(ERRCODE_SYNTAX_ERROR),
1410 errmsg("conflicting or redundant options")));
1411 failover_given = true;
1412 failover = defGetBoolean(defel);
1413 }
1414 else if (strcmp(defel->defname, "two_phase") == 0)
1415 {
1416 if (two_phase_given)
1417 ereport(ERROR,
1418 (errcode(ERRCODE_SYNTAX_ERROR),
1419 errmsg("conflicting or redundant options")));
1420 two_phase_given = true;
1421 two_phase = defGetBoolean(defel);
1422 }
1423 else
1424 elog(ERROR, "unrecognized option: %s", defel->defname);
1425 }
1426
1428 failover_given ? &failover : NULL,
1429 two_phase_given ? &two_phase : NULL);
1430}
bool defGetBoolean(DefElem *def)
Definition: define.c:94
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
#define foreach_ptr(type, var, lst)
Definition: pg_list.h:469
static bool two_phase
static bool failover
void ReplicationSlotAlter(const char *name, const bool *failover, const bool *two_phase)
Definition: slot.c:882

References defGetBoolean(), elog, ereport, errcode(), errmsg(), ERROR, failover, foreach_ptr, AlterReplicationSlotCmd::options, ReplicationSlotAlter(), AlterReplicationSlotCmd::slotname, and two_phase.

Referenced by exec_replication_command().

◆ CreateReplicationSlot()

static void CreateReplicationSlot ( CreateReplicationSlotCmd cmd)
static

Definition at line 1181 of file walsender.c.

1182{
1183 const char *snapshot_name = NULL;
1184 char xloc[MAXFNAMELEN];
1185 char *slot_name;
1186 bool reserve_wal = false;
1187 bool two_phase = false;
1188 bool failover = false;
1189 CRSSnapshotAction snapshot_action = CRS_EXPORT_SNAPSHOT;
1191 TupOutputState *tstate;
1192 TupleDesc tupdesc;
1193 Datum values[4];
1194 bool nulls[4] = {0};
1195
1197
1198 parseCreateReplSlotOptions(cmd, &reserve_wal, &snapshot_action, &two_phase,
1199 &failover);
1200
1201 if (cmd->kind == REPLICATION_KIND_PHYSICAL)
1202 {
1203 ReplicationSlotCreate(cmd->slotname, false,
1205 false, false, false);
1206
1207 if (reserve_wal)
1208 {
1210
1212
1213 /* Write this slot to disk if it's a permanent one. */
1214 if (!cmd->temporary)
1216 }
1217 }
1218 else
1219 {
1221 bool need_full_snapshot = false;
1222
1224
1226
1227 /*
1228 * Initially create persistent slot as ephemeral - that allows us to
1229 * nicely handle errors during initialization because it'll get
1230 * dropped if this transaction fails. We'll make it persistent at the
1231 * end. Temporary slots can be created as temporary from beginning as
1232 * they get dropped on error as well.
1233 */
1236 two_phase, failover, false);
1237
1238 /*
1239 * Do options check early so that we can bail before calling the
1240 * DecodingContextFindStartpoint which can take long time.
1241 */
1242 if (snapshot_action == CRS_EXPORT_SNAPSHOT)
1243 {
1244 if (IsTransactionBlock())
1245 ereport(ERROR,
1246 /*- translator: %s is a CREATE_REPLICATION_SLOT statement */
1247 (errmsg("%s must not be called inside a transaction",
1248 "CREATE_REPLICATION_SLOT ... (SNAPSHOT 'export')")));
1249
1250 need_full_snapshot = true;
1251 }
1252 else if (snapshot_action == CRS_USE_SNAPSHOT)
1253 {
1254 if (!IsTransactionBlock())
1255 ereport(ERROR,
1256 /*- translator: %s is a CREATE_REPLICATION_SLOT statement */
1257 (errmsg("%s must be called inside a transaction",
1258 "CREATE_REPLICATION_SLOT ... (SNAPSHOT 'use')")));
1259
1261 ereport(ERROR,
1262 /*- translator: %s is a CREATE_REPLICATION_SLOT statement */
1263 (errmsg("%s must be called in REPEATABLE READ isolation mode transaction",
1264 "CREATE_REPLICATION_SLOT ... (SNAPSHOT 'use')")));
1265 if (!XactReadOnly)
1266 ereport(ERROR,
1267 /*- translator: %s is a CREATE_REPLICATION_SLOT statement */
1268 (errmsg("%s must be called in a read-only transaction",
1269 "CREATE_REPLICATION_SLOT ... (SNAPSHOT 'use')")));
1270
1271 if (FirstSnapshotSet)
1272 ereport(ERROR,
1273 /*- translator: %s is a CREATE_REPLICATION_SLOT statement */
1274 (errmsg("%s must be called before any query",
1275 "CREATE_REPLICATION_SLOT ... (SNAPSHOT 'use')")));
1276
1277 if (IsSubTransaction())
1278 ereport(ERROR,
1279 /*- translator: %s is a CREATE_REPLICATION_SLOT statement */
1280 (errmsg("%s must not be called in a subtransaction",
1281 "CREATE_REPLICATION_SLOT ... (SNAPSHOT 'use')")));
1282
1283 need_full_snapshot = true;
1284 }
1285
1286 ctx = CreateInitDecodingContext(cmd->plugin, NIL, need_full_snapshot,
1289 .segment_open = WalSndSegmentOpen,
1290 .segment_close = wal_segment_close),
1293
1294 /*
1295 * Signal that we don't need the timeout mechanism. We're just
1296 * creating the replication slot and don't yet accept feedback
1297 * messages or send keepalives. As we possibly need to wait for
1298 * further WAL the walsender would otherwise possibly be killed too
1299 * soon.
1300 */
1302
1303 /* build initial snapshot, might take a while */
1305
1306 /*
1307 * Export or use the snapshot if we've been asked to do so.
1308 *
1309 * NB. We will convert the snapbuild.c kind of snapshot to normal
1310 * snapshot when doing this.
1311 */
1312 if (snapshot_action == CRS_EXPORT_SNAPSHOT)
1313 {
1314 snapshot_name = SnapBuildExportSnapshot(ctx->snapshot_builder);
1315 }
1316 else if (snapshot_action == CRS_USE_SNAPSHOT)
1317 {
1318 Snapshot snap;
1319
1322 }
1323
1324 /* don't need the decoding context anymore */
1326
1327 if (!cmd->temporary)
1329 }
1330
1331 snprintf(xloc, sizeof(xloc), "%X/%08X",
1333
1335
1336 /*----------
1337 * Need a tuple descriptor representing four columns:
1338 * - first field: the slot name
1339 * - second field: LSN at which we became consistent
1340 * - third field: exported snapshot's name
1341 * - fourth field: output plugin
1342 */
1343 tupdesc = CreateTemplateTupleDesc(4);
1344 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "slot_name",
1345 TEXTOID, -1, 0);
1346 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "consistent_point",
1347 TEXTOID, -1, 0);
1348 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "snapshot_name",
1349 TEXTOID, -1, 0);
1350 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 4, "output_plugin",
1351 TEXTOID, -1, 0);
1352
1353 /* prepare for projection of tuples */
1354 tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
1355
1356 /* slot_name */
1357 slot_name = NameStr(MyReplicationSlot->data.name);
1358 values[0] = CStringGetTextDatum(slot_name);
1359
1360 /* consistent wal location */
1361 values[1] = CStringGetTextDatum(xloc);
1362
1363 /* snapshot name, or NULL if none */
1364 if (snapshot_name != NULL)
1365 values[2] = CStringGetTextDatum(snapshot_name);
1366 else
1367 nulls[2] = true;
1368
1369 /* plugin, or NULL if none */
1370 if (cmd->plugin != NULL)
1372 else
1373 nulls[3] = true;
1374
1375 /* send it to dest */
1376 do_tup_output(tstate, values, nulls);
1377 end_tup_output(tstate);
1378
1380}
int16 AttrNumber
Definition: attnum.h:21
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define NameStr(name)
Definition: c.h:751
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
@ DestRemoteSimple
Definition: dest.h:91
void do_tup_output(TupOutputState *tstate, const Datum *values, const bool *isnull)
Definition: execTuples.c:2464
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
void end_tup_output(TupOutputState *tstate)
Definition: execTuples.c:2522
TupOutputState * begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:2444
Assert(PointerIsAligned(start, uint64))
void FreeDecodingContext(LogicalDecodingContext *ctx)
Definition: logical.c:677
void DecodingContextFindStartpoint(LogicalDecodingContext *ctx)
Definition: logical.c:633
LogicalDecodingContext * CreateInitDecodingContext(const char *plugin, List *output_plugin_options, bool need_full_snapshot, XLogRecPtr restart_lsn, XLogReaderRoutine *xl_routine, LogicalOutputPluginWriterPrepareWrite prepare_write, LogicalOutputPluginWriterWrite do_write, LogicalOutputPluginWriterUpdateProgress update_progress)
Definition: logical.c:332
void CheckLogicalDecodingRequirements(void)
Definition: logical.c:111
#define NIL
Definition: pg_list.h:68
#define snprintf
Definition: port.h:239
uint64_t Datum
Definition: postgres.h:70
@ REPLICATION_KIND_PHYSICAL
Definition: replnodes.h:22
@ REPLICATION_KIND_LOGICAL
Definition: replnodes.h:23
void ReplicationSlotCreate(const char *name, bool db_specific, ReplicationSlotPersistency persistency, bool two_phase, bool failover, bool synced)
Definition: slot.c:352
void ReplicationSlotMarkDirty(void)
Definition: slot.c:1106
void ReplicationSlotReserveWal(void)
Definition: slot.c:1539
void ReplicationSlotPersist(void)
Definition: slot.c:1123
ReplicationSlot * MyReplicationSlot
Definition: slot.c:148
void ReplicationSlotSave(void)
Definition: slot.c:1088
void ReplicationSlotRelease(void)
Definition: slot.c:731
@ RS_PERSISTENT
Definition: slot.h:45
@ RS_EPHEMERAL
Definition: slot.h:46
@ RS_TEMPORARY
Definition: slot.h:47
Snapshot SnapBuildInitialSnapshot(SnapBuild *builder)
Definition: snapbuild.c:440
const char * SnapBuildExportSnapshot(SnapBuild *builder)
Definition: snapbuild.c:539
bool FirstSnapshotSet
Definition: snapmgr.c:192
void RestoreTransactionSnapshot(Snapshot snapshot, void *source_pgproc)
Definition: snapmgr.c:1854
PGPROC * MyProc
Definition: proc.c:66
ReplicationKind kind
Definition: replnodes.h:56
struct SnapBuild * snapshot_builder
Definition: logical.h:44
XLogRecPtr confirmed_flush
Definition: slot.h:118
ReplicationSlotPersistentData data
Definition: slot.h:192
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:182
void TupleDescInitBuiltinEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:918
static void parseCreateReplSlotOptions(CreateReplicationSlotCmd *cmd, bool *reserve_wal, CRSSnapshotAction *snapshot_action, bool *two_phase, bool *failover)
Definition: walsender.c:1104
static void WalSndSegmentOpen(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
Definition: walsender.c:3093
static void WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid, bool last_write)
Definition: walsender.c:1557
static void WalSndUpdateProgress(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid, bool skipped_xact)
Definition: walsender.c:1653
static int logical_read_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *cur_page)
Definition: walsender.c:1031
static void WalSndPrepareWrite(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid, bool last_write)
Definition: walsender.c:1530
static TimestampTz last_reply_timestamp
Definition: walsender.c:187
CRSSnapshotAction
Definition: walsender.h:21
@ CRS_USE_SNAPSHOT
Definition: walsender.h:24
@ CRS_EXPORT_SNAPSHOT
Definition: walsender.h:22
bool XactReadOnly
Definition: xact.c:82
int XactIsoLevel
Definition: xact.c:79
bool IsSubTransaction(void)
Definition: xact.c:5056
bool IsTransactionBlock(void)
Definition: xact.c:4983
#define XACT_REPEATABLE_READ
Definition: xact.h:38
#define MAXFNAMELEN
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:46
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
#define XL_ROUTINE(...)
Definition: xlogreader.h:117
void wal_segment_close(XLogReaderState *state)
Definition: xlogutils.c:831

References Assert(), begin_tup_output_tupdesc(), CheckLogicalDecodingRequirements(), ReplicationSlotPersistentData::confirmed_flush, CreateDestReceiver(), CreateInitDecodingContext(), CreateTemplateTupleDesc(), CRS_EXPORT_SNAPSHOT, CRS_USE_SNAPSHOT, CStringGetTextDatum, ReplicationSlot::data, DecodingContextFindStartpoint(), generate_unaccent_rules::dest, DestRemoteSimple, do_tup_output(), end_tup_output(), ereport, errmsg(), ERROR, failover, FirstSnapshotSet, FreeDecodingContext(), InvalidXLogRecPtr, IsSubTransaction(), IsTransactionBlock(), CreateReplicationSlotCmd::kind, last_reply_timestamp, logical_read_xlog_page(), LSN_FORMAT_ARGS, MAXFNAMELEN, MyProc, MyReplicationSlot, ReplicationSlotPersistentData::name, NameStr, NIL, parseCreateReplSlotOptions(), CreateReplicationSlotCmd::plugin, REPLICATION_KIND_LOGICAL, REPLICATION_KIND_PHYSICAL, ReplicationSlotCreate(), ReplicationSlotMarkDirty(), ReplicationSlotPersist(), ReplicationSlotRelease(), ReplicationSlotReserveWal(), ReplicationSlotSave(), RestoreTransactionSnapshot(), RS_EPHEMERAL, RS_PERSISTENT, RS_TEMPORARY, CreateReplicationSlotCmd::slotname, SnapBuildExportSnapshot(), SnapBuildInitialSnapshot(), LogicalDecodingContext::snapshot_builder, snprintf, CreateReplicationSlotCmd::temporary, TTSOpsVirtual, TupleDescInitBuiltinEntry(), two_phase, values, wal_segment_close(), WalSndPrepareWrite(), WalSndSegmentOpen(), WalSndUpdateProgress(), WalSndWriteData(), XACT_REPEATABLE_READ, XactIsoLevel, XactReadOnly, and XL_ROUTINE.

Referenced by exec_replication_command(), main(), and StartLogStreamer().

◆ DropReplicationSlot()

static void DropReplicationSlot ( DropReplicationSlotCmd cmd)
static

Definition at line 1386 of file walsender.c.

1387{
1388 ReplicationSlotDrop(cmd->slotname, !cmd->wait);
1389}
void ReplicationSlotDrop(const char *name, bool nowait)
Definition: slot.c:859

References ReplicationSlotDrop(), DropReplicationSlotCmd::slotname, and DropReplicationSlotCmd::wait.

Referenced by exec_replication_command(), and main().

◆ exec_replication_command()

bool exec_replication_command ( const char *  cmd_string)

Definition at line 1974 of file walsender.c.

1975{
1976 yyscan_t scanner;
1977 int parse_rc;
1978 Node *cmd_node;
1979 const char *cmdtag;
1980 MemoryContext old_context = CurrentMemoryContext;
1981
1982 /* We save and re-use the cmd_context across calls */
1983 static MemoryContext cmd_context = NULL;
1984
1985 /*
1986 * If WAL sender has been told that shutdown is getting close, switch its
1987 * status accordingly to handle the next replication commands correctly.
1988 */
1989 if (got_STOPPING)
1991
1992 /*
1993 * Throw error if in stopping mode. We need prevent commands that could
1994 * generate WAL while the shutdown checkpoint is being written. To be
1995 * safe, we just prohibit all new commands.
1996 */
1998 ereport(ERROR,
1999 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2000 errmsg("cannot execute new commands while WAL sender is in stopping mode")));
2001
2002 /*
2003 * CREATE_REPLICATION_SLOT ... LOGICAL exports a snapshot until the next
2004 * command arrives. Clean up the old stuff if there's anything.
2005 */
2007
2009
2010 /*
2011 * Prepare to parse and execute the command.
2012 *
2013 * Because replication command execution can involve beginning or ending
2014 * transactions, we need a working context that will survive that, so we
2015 * make it a child of TopMemoryContext. That in turn creates a hazard of
2016 * long-lived memory leaks if we lose track of the working context. We
2017 * deal with that by creating it only once per walsender, and resetting it
2018 * for each new command. (Normally this reset is a no-op, but if the
2019 * prior exec_replication_command call failed with an error, it won't be.)
2020 *
2021 * This is subtler than it looks. The transactions we manage can extend
2022 * across replication commands, indeed SnapBuildClearExportedSnapshot
2023 * might have just ended one. Because transaction exit will revert to the
2024 * memory context that was current at transaction start, we need to be
2025 * sure that that context is still valid. That motivates re-using the
2026 * same cmd_context rather than making a new one each time.
2027 */
2028 if (cmd_context == NULL)
2030 "Replication command context",
2032 else
2033 MemoryContextReset(cmd_context);
2034
2035 MemoryContextSwitchTo(cmd_context);
2036
2037 replication_scanner_init(cmd_string, &scanner);
2038
2039 /*
2040 * Is it a WalSender command?
2041 */
2043 {
2044 /* Nope; clean up and get out. */
2046
2047 MemoryContextSwitchTo(old_context);
2048 MemoryContextReset(cmd_context);
2049
2050 /* XXX this is a pretty random place to make this check */
2051 if (MyDatabaseId == InvalidOid)
2052 ereport(ERROR,
2053 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2054 errmsg("cannot execute SQL commands in WAL sender for physical replication")));
2055
2056 /* Tell the caller that this wasn't a WalSender command. */
2057 return false;
2058 }
2059
2060 /*
2061 * Looks like a WalSender command, so parse it.
2062 */
2063 parse_rc = replication_yyparse(&cmd_node, scanner);
2064 if (parse_rc != 0)
2065 ereport(ERROR,
2066 (errcode(ERRCODE_SYNTAX_ERROR),
2067 errmsg_internal("replication command parser returned %d",
2068 parse_rc)));
2070
2071 /*
2072 * Report query to various monitoring facilities. For this purpose, we
2073 * report replication commands just like SQL commands.
2074 */
2075 debug_query_string = cmd_string;
2076
2078
2079 /*
2080 * Log replication command if log_replication_commands is enabled. Even
2081 * when it's disabled, log the command with DEBUG1 level for backward
2082 * compatibility.
2083 */
2085 (errmsg("received replication command: %s", cmd_string)));
2086
2087 /*
2088 * Disallow replication commands in aborted transaction blocks.
2089 */
2091 ereport(ERROR,
2092 (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
2093 errmsg("current transaction is aborted, "
2094 "commands ignored until end of transaction block")));
2095
2097
2098 /*
2099 * Allocate buffers that will be used for each outgoing and incoming
2100 * message. We do this just once per command to reduce palloc overhead.
2101 */
2105
2106 switch (cmd_node->type)
2107 {
2108 case T_IdentifySystemCmd:
2109 cmdtag = "IDENTIFY_SYSTEM";
2110 set_ps_display(cmdtag);
2112 EndReplicationCommand(cmdtag);
2113 break;
2114
2115 case T_ReadReplicationSlotCmd:
2116 cmdtag = "READ_REPLICATION_SLOT";
2117 set_ps_display(cmdtag);
2119 EndReplicationCommand(cmdtag);
2120 break;
2121
2122 case T_BaseBackupCmd:
2123 cmdtag = "BASE_BACKUP";
2124 set_ps_display(cmdtag);
2125 PreventInTransactionBlock(true, cmdtag);
2127 EndReplicationCommand(cmdtag);
2128 break;
2129
2130 case T_CreateReplicationSlotCmd:
2131 cmdtag = "CREATE_REPLICATION_SLOT";
2132 set_ps_display(cmdtag);
2134 EndReplicationCommand(cmdtag);
2135 break;
2136
2137 case T_DropReplicationSlotCmd:
2138 cmdtag = "DROP_REPLICATION_SLOT";
2139 set_ps_display(cmdtag);
2141 EndReplicationCommand(cmdtag);
2142 break;
2143
2144 case T_AlterReplicationSlotCmd:
2145 cmdtag = "ALTER_REPLICATION_SLOT";
2146 set_ps_display(cmdtag);
2148 EndReplicationCommand(cmdtag);
2149 break;
2150
2151 case T_StartReplicationCmd:
2152 {
2153 StartReplicationCmd *cmd = (StartReplicationCmd *) cmd_node;
2154
2155 cmdtag = "START_REPLICATION";
2156 set_ps_display(cmdtag);
2157 PreventInTransactionBlock(true, cmdtag);
2158
2159 if (cmd->kind == REPLICATION_KIND_PHYSICAL)
2160 StartReplication(cmd);
2161 else
2163
2164 /* dupe, but necessary per libpqrcv_endstreaming */
2165 EndReplicationCommand(cmdtag);
2166
2167 Assert(xlogreader != NULL);
2168 break;
2169 }
2170
2171 case T_TimeLineHistoryCmd:
2172 cmdtag = "TIMELINE_HISTORY";
2173 set_ps_display(cmdtag);
2174 PreventInTransactionBlock(true, cmdtag);
2176 EndReplicationCommand(cmdtag);
2177 break;
2178
2179 case T_VariableShowStmt:
2180 {
2182 VariableShowStmt *n = (VariableShowStmt *) cmd_node;
2183
2184 cmdtag = "SHOW";
2185 set_ps_display(cmdtag);
2186
2187 /* syscache access needs a transaction environment */
2189 GetPGVariable(n->name, dest);
2191 EndReplicationCommand(cmdtag);
2192 }
2193 break;
2194
2195 case T_UploadManifestCmd:
2196 cmdtag = "UPLOAD_MANIFEST";
2197 set_ps_display(cmdtag);
2198 PreventInTransactionBlock(true, cmdtag);
2200 EndReplicationCommand(cmdtag);
2201 break;
2202
2203 default:
2204 elog(ERROR, "unrecognized replication command node tag: %u",
2205 cmd_node->type);
2206 }
2207
2208 /*
2209 * Done. Revert to caller's memory context, and clean out the cmd_context
2210 * to recover memory right away.
2211 */
2212 MemoryContextSwitchTo(old_context);
2213 MemoryContextReset(cmd_context);
2214
2215 /*
2216 * We need not update ps display or pg_stat_activity, because PostgresMain
2217 * will reset those to "idle". But we must reset debug_query_string to
2218 * ensure it doesn't become a dangling pointer.
2219 */
2220 debug_query_string = NULL;
2221
2222 return true;
2223}
void pgstat_report_activity(BackendState state, const char *cmd_str)
@ STATE_RUNNING
void SendBaseBackup(BaseBackupCmd *cmd, IncrementalBackupInfo *ib)
Definition: basebackup.c:990
void * yyscan_t
Definition: cubedata.h:65
void EndReplicationCommand(const char *commandTag)
Definition: dest.c:205
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1161
#define LOG
Definition: elog.h:31
#define DEBUG1
Definition: elog.h:30
Oid MyDatabaseId
Definition: globals.c:94
void GetPGVariable(const char *name, DestReceiver *dest)
Definition: guc_funcs.c:382
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
MemoryContext TopMemoryContext
Definition: mcxt.c:166
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
const char * debug_query_string
Definition: postgres.c:88
#define InvalidOid
Definition: postgres_ext.h:37
static void set_ps_display(const char *activity)
Definition: ps_status.h:40
bool replication_scanner_is_replication_command(yyscan_t yyscanner)
Definition: repl_scanner.l:299
void replication_scanner_finish(yyscan_t yyscanner)
Definition: repl_scanner.l:284
void replication_scanner_init(const char *str, yyscan_t *yyscannerp)
Definition: repl_scanner.l:268
void SnapBuildClearExportedSnapshot(void)
Definition: snapbuild.c:600
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
Definition: nodes.h:135
NodeTag type
Definition: nodes.h:136
ReplicationKind kind
Definition: replnodes.h:94
WalSndState state
static void AlterReplicationSlot(AlterReplicationSlotCmd *cmd)
Definition: walsender.c:1395
static void SendTimeLineHistory(TimeLineHistoryCmd *cmd)
Definition: walsender.c:567
WalSnd * MyWalSnd
Definition: walsender.c:120
static void ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
Definition: walsender.c:468
static StringInfoData tmpbuf
Definition: walsender.c:178
static void IdentifySystem(void)
Definition: walsender.c:387
static StringInfoData reply_message
Definition: walsender.c:177
void WalSndSetState(WalSndState state)
Definition: walsender.c:3922
static StringInfoData output_message
Definition: walsender.c:176
static void UploadManifest(void)
Definition: walsender.c:657
static volatile sig_atomic_t got_STOPPING
Definition: walsender.c:206
bool log_replication_commands
Definition: walsender.c:133
static void CreateReplicationSlot(CreateReplicationSlotCmd *cmd)
Definition: walsender.c:1181
static void StartLogicalReplication(StartReplicationCmd *cmd)
Definition: walsender.c:1437
static IncrementalBackupInfo * uploaded_manifest
Definition: walsender.c:155
static void DropReplicationSlot(DropReplicationSlotCmd *cmd)
Definition: walsender.c:1386
static void StartReplication(StartReplicationCmd *cmd)
Definition: walsender.c:799
static XLogReaderState * xlogreader
Definition: walsender.c:145
@ WALSNDSTATE_STOPPING
int replication_yyparse(Node **replication_parse_result_p, yyscan_t yyscanner)
void PreventInTransactionBlock(bool isTopLevel, const char *stmtType)
Definition: xact.c:3660
void StartTransactionCommand(void)
Definition: xact.c:3071
bool IsAbortedTransactionBlockState(void)
Definition: xact.c:407
void CommitTransactionCommand(void)
Definition: xact.c:3169

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, AlterReplicationSlot(), Assert(), CHECK_FOR_INTERRUPTS, CommitTransactionCommand(), CreateDestReceiver(), CreateReplicationSlot(), CurrentMemoryContext, DEBUG1, debug_query_string, generate_unaccent_rules::dest, DestRemoteSimple, DropReplicationSlot(), elog, EndReplicationCommand(), ereport, errcode(), errmsg(), errmsg_internal(), ERROR, GetPGVariable(), got_STOPPING, IdentifySystem(), initStringInfo(), InvalidOid, IsAbortedTransactionBlockState(), StartReplicationCmd::kind, LOG, log_replication_commands, MemoryContextReset(), MemoryContextSwitchTo(), MyDatabaseId, MyWalSnd, VariableShowStmt::name, output_message, pgstat_report_activity(), PreventInTransactionBlock(), ReadReplicationSlot(), REPLICATION_KIND_PHYSICAL, replication_scanner_finish(), replication_scanner_init(), replication_scanner_is_replication_command(), replication_yyparse(), reply_message, SendBaseBackup(), SendTimeLineHistory(), set_ps_display(), SnapBuildClearExportedSnapshot(), StartLogicalReplication(), StartReplication(), StartTransactionCommand(), WalSnd::state, STATE_RUNNING, tmpbuf, TopMemoryContext, Node::type, ReadReplicationSlotCmd::type, uploaded_manifest, UploadManifest(), WalSndSetState(), WALSNDSTATE_STOPPING, and xlogreader.

Referenced by PostgresMain().

◆ GetStandbyFlushRecPtr()

XLogRecPtr GetStandbyFlushRecPtr ( TimeLineID tli)

Definition at line 3617 of file walsender.c.

3618{
3619 XLogRecPtr replayPtr;
3620 TimeLineID replayTLI;
3621 XLogRecPtr receivePtr;
3623 XLogRecPtr result;
3624
3626
3627 /*
3628 * We can safely send what's already been replayed. Also, if walreceiver
3629 * is streaming WAL from the same timeline, we can send anything that it
3630 * has streamed, but hasn't been replayed yet.
3631 */
3632
3633 receivePtr = GetWalRcvFlushRecPtr(NULL, &receiveTLI);
3634 replayPtr = GetXLogReplayRecPtr(&replayTLI);
3635
3636 if (tli)
3637 *tli = replayTLI;
3638
3639 result = replayPtr;
3640 if (receiveTLI == replayTLI && receivePtr > replayPtr)
3641 result = receivePtr;
3642
3643 return result;
3644}
bool IsSyncingReplicationSlots(void)
Definition: slotsync.c:1668
XLogRecPtr GetWalRcvFlushRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI)
bool am_cascading_walsender
Definition: walsender.c:124
uint64 XLogRecPtr
Definition: xlogdefs.h:21
uint32 TimeLineID
Definition: xlogdefs.h:62
static TimeLineID receiveTLI
Definition: xlogrecovery.c:265
XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI)

References am_cascading_walsender, Assert(), GetWalRcvFlushRecPtr(), GetXLogReplayRecPtr(), IsSyncingReplicationSlots(), and receiveTLI.

Referenced by IdentifySystem(), StartReplication(), synchronize_one_slot(), and XLogSendPhysical().

◆ HandleUploadManifestPacket()

static bool HandleUploadManifestPacket ( StringInfo  buf,
off_t *  offset,
IncrementalBackupInfo ib 
)
static

Definition at line 723 of file walsender.c.

725{
726 int mtype;
727 int maxmsglen;
728
730
732 mtype = pq_getbyte();
733 if (mtype == EOF)
735 (errcode(ERRCODE_CONNECTION_FAILURE),
736 errmsg("unexpected EOF on client connection with an open transaction")));
737
738 switch (mtype)
739 {
740 case PqMsg_CopyData:
741 maxmsglen = PQ_LARGE_MESSAGE_LIMIT;
742 break;
743 case PqMsg_CopyDone:
744 case PqMsg_CopyFail:
745 case PqMsg_Flush:
746 case PqMsg_Sync:
747 maxmsglen = PQ_SMALL_MESSAGE_LIMIT;
748 break;
749 default:
751 (errcode(ERRCODE_PROTOCOL_VIOLATION),
752 errmsg("unexpected message type 0x%02X during COPY from stdin",
753 mtype)));
754 maxmsglen = 0; /* keep compiler quiet */
755 break;
756 }
757
758 /* Now collect the message body */
759 if (pq_getmessage(buf, maxmsglen))
761 (errcode(ERRCODE_CONNECTION_FAILURE),
762 errmsg("unexpected EOF on client connection with an open transaction")));
764
765 /* Process the message */
766 switch (mtype)
767 {
768 case PqMsg_CopyData:
769 AppendIncrementalManifestData(ib, buf->data, buf->len);
770 return true;
771
772 case PqMsg_CopyDone:
773 return false;
774
775 case PqMsg_Sync:
776 case PqMsg_Flush:
777 /* Ignore these while in CopyOut mode as we do elsewhere. */
778 return true;
779
780 case PqMsg_CopyFail:
782 (errcode(ERRCODE_QUERY_CANCELED),
783 errmsg("COPY from stdin failed: %s",
785 }
786
787 /* Not reached. */
788 Assert(false);
789 return false;
790}
void AppendIncrementalManifestData(IncrementalBackupInfo *ib, const char *data, int len)
#define PQ_SMALL_MESSAGE_LIMIT
Definition: libpq.h:30
#define PQ_LARGE_MESSAGE_LIMIT
Definition: libpq.h:31
#define HOLD_CANCEL_INTERRUPTS()
Definition: miscadmin.h:141
#define RESUME_CANCEL_INTERRUPTS()
Definition: miscadmin.h:143
static char * buf
Definition: pg_test_fsync.c:72
int pq_getmessage(StringInfo s, int maxlen)
Definition: pqcomm.c:1203
int pq_getbyte(void)
Definition: pqcomm.c:963
void pq_startmsgread(void)
Definition: pqcomm.c:1141
const char * pq_getmsgstring(StringInfo msg)
Definition: pqformat.c:579
#define PqMsg_CopyDone
Definition: protocol.h:64
#define PqMsg_CopyData
Definition: protocol.h:65
#define PqMsg_Sync
Definition: protocol.h:27
#define PqMsg_CopyFail
Definition: protocol.h:29
#define PqMsg_Flush
Definition: protocol.h:24

References AppendIncrementalManifestData(), Assert(), buf, ereport, errcode(), errmsg(), ERROR, HOLD_CANCEL_INTERRUPTS, pq_getbyte(), pq_getmessage(), pq_getmsgstring(), PQ_LARGE_MESSAGE_LIMIT, PQ_SMALL_MESSAGE_LIMIT, pq_startmsgread(), PqMsg_CopyData, PqMsg_CopyDone, PqMsg_CopyFail, PqMsg_Flush, PqMsg_Sync, and RESUME_CANCEL_INTERRUPTS.

Referenced by UploadManifest().

◆ HandleWalSndInitStopping()

void HandleWalSndInitStopping ( void  )

Definition at line 3673 of file walsender.c.

3674{
3676
3677 /*
3678 * If replication has not yet started, die like with SIGTERM. If
3679 * replication is active, only set a flag and wake up the main loop. It
3680 * will send any outstanding WAL, wait for it to be replicated to the
3681 * standby, and then exit gracefully.
3682 */
3683 if (!replication_active)
3684 kill(MyProcPid, SIGTERM);
3685 else
3686 got_STOPPING = true;
3687}
int MyProcPid
Definition: globals.c:47
bool am_walsender
Definition: walsender.c:123
static volatile sig_atomic_t replication_active
Definition: walsender.c:214
#define kill(pid, sig)
Definition: win32_port.h:493

References am_walsender, Assert(), got_STOPPING, kill, MyProcPid, and replication_active.

Referenced by procsignal_sigusr1_handler().

◆ IdentifySystem()

static void IdentifySystem ( void  )
static

Definition at line 387 of file walsender.c.

388{
389 char sysid[32];
390 char xloc[MAXFNAMELEN];
391 XLogRecPtr logptr;
392 char *dbname = NULL;
394 TupOutputState *tstate;
395 TupleDesc tupdesc;
396 Datum values[4];
397 bool nulls[4] = {0};
398 TimeLineID currTLI;
399
400 /*
401 * Reply with a result set with one row, four columns. First col is system
402 * ID, second is timeline ID, third is current xlog location and the
403 * fourth contains the database name if we are connected to one.
404 */
405
406 snprintf(sysid, sizeof(sysid), UINT64_FORMAT,
408
411 logptr = GetStandbyFlushRecPtr(&currTLI);
412 else
413 logptr = GetFlushRecPtr(&currTLI);
414
415 snprintf(xloc, sizeof(xloc), "%X/%08X", LSN_FORMAT_ARGS(logptr));
416
418 {
420
421 /* syscache access needs a transaction env. */
424 /* copy dbname out of TX context */
427 }
428
430
431 /* need a tuple descriptor representing four columns */
432 tupdesc = CreateTemplateTupleDesc(4);
433 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "systemid",
434 TEXTOID, -1, 0);
435 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "timeline",
436 INT8OID, -1, 0);
437 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "xlogpos",
438 TEXTOID, -1, 0);
439 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 4, "dbname",
440 TEXTOID, -1, 0);
441
442 /* prepare for projection of tuples */
443 tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
444
445 /* column 1: system identifier */
446 values[0] = CStringGetTextDatum(sysid);
447
448 /* column 2: timeline */
449 values[1] = Int64GetDatum(currTLI);
450
451 /* column 3: wal location */
452 values[2] = CStringGetTextDatum(xloc);
453
454 /* column 4: database name, or NULL if none */
455 if (dbname)
457 else
458 nulls[3] = true;
459
460 /* send it to dest */
461 do_tup_output(tstate, values, nulls);
462
463 end_tup_output(tstate);
464}
#define UINT64_FORMAT
Definition: c.h:557
struct cursor * cur
Definition: ecpg.c:29
char * get_database_name(Oid dbid)
Definition: lsyscache.c:1259
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1746
static Datum Int64GetDatum(int64 X)
Definition: postgres.h:403
char * dbname
Definition: streamutil.c:49
XLogRecPtr GetStandbyFlushRecPtr(TimeLineID *tli)
Definition: walsender.c:3617
uint64 GetSystemIdentifier(void)
Definition: xlog.c:4595
bool RecoveryInProgress(void)
Definition: xlog.c:6386
XLogRecPtr GetFlushRecPtr(TimeLineID *insertTLI)
Definition: xlog.c:6551

References am_cascading_walsender, begin_tup_output_tupdesc(), CommitTransactionCommand(), CreateDestReceiver(), CreateTemplateTupleDesc(), CStringGetTextDatum, cur, CurrentMemoryContext, dbname, generate_unaccent_rules::dest, DestRemoteSimple, do_tup_output(), end_tup_output(), get_database_name(), GetFlushRecPtr(), GetStandbyFlushRecPtr(), GetSystemIdentifier(), Int64GetDatum(), InvalidOid, LSN_FORMAT_ARGS, MAXFNAMELEN, MemoryContextStrdup(), MyDatabaseId, RecoveryInProgress(), snprintf, StartTransactionCommand(), TTSOpsVirtual, TupleDescInitBuiltinEntry(), UINT64_FORMAT, and values.

Referenced by exec_replication_command().

◆ InitWalSender()

void InitWalSender ( void  )

Definition at line 287 of file walsender.c.

288{
290
291 /* Create a per-walsender data structure in shared memory */
293
294 /* need resource owner for e.g. basebackups */
296
297 /*
298 * Let postmaster know that we're a WAL sender. Once we've declared us as
299 * a WAL sender process, postmaster will let us outlive the bgwriter and
300 * kill us last in the shutdown sequence, so we get a chance to stream all
301 * remaining WAL at shutdown, including the shutdown checkpoint. Note that
302 * there's no going back, and we mustn't write any WAL records after this.
303 */
306
307 /*
308 * If the client didn't specify a database to connect to, show in PGPROC
309 * that our advertised xmin should affect vacuum horizons in all
310 * databases. This allows physical replication clients to send hot
311 * standby feedback that will delay vacuum cleanup in all databases.
312 */
314 {
316 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
319 LWLockRelease(ProcArrayLock);
320 }
321
322 /* Initialize empty timestamp buffer for lag tracking. */
324}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_EXCLUSIVE
Definition: lwlock.h:112
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1263
void SendPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:165
void MarkPostmasterChildWalSender(void)
Definition: pmsignal.c:309
@ PMSIGNAL_ADVANCE_STATE_MACHINE
Definition: pmsignal.h:43
#define PROC_AFFECTS_ALL_HORIZONS
Definition: proc.h:62
void CreateAuxProcessResourceOwner(void)
Definition: resowner.c:996
PROC_HDR * ProcGlobal
Definition: proc.c:78
TransactionId xmin
Definition: proc.h:194
uint8 statusFlags
Definition: proc.h:259
int pgxactoff
Definition: proc.h:201
uint8 * statusFlags
Definition: proc.h:403
#define InvalidTransactionId
Definition: transam.h:31
static void InitWalSenderSlot(void)
Definition: walsender.c:3001
static LagTracker * lag_tracker
Definition: walsender.c:238

References am_cascading_walsender, Assert(), CreateAuxProcessResourceOwner(), InitWalSenderSlot(), InvalidOid, InvalidTransactionId, lag_tracker, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MarkPostmasterChildWalSender(), MemoryContextAllocZero(), MyDatabaseId, MyProc, PGPROC::pgxactoff, PMSIGNAL_ADVANCE_STATE_MACHINE, PROC_AFFECTS_ALL_HORIZONS, ProcGlobal, RecoveryInProgress(), SendPostmasterSignal(), PGPROC::statusFlags, PROC_HDR::statusFlags, TopMemoryContext, and PGPROC::xmin.

Referenced by PostgresMain().

◆ InitWalSenderSlot()

static void InitWalSenderSlot ( void  )
static

Definition at line 3001 of file walsender.c.

3002{
3003 int i;
3004
3005 /*
3006 * WalSndCtl should be set up already (we inherit this by fork() or
3007 * EXEC_BACKEND mechanism from the postmaster).
3008 */
3009 Assert(WalSndCtl != NULL);
3010 Assert(MyWalSnd == NULL);
3011
3012 /*
3013 * Find a free walsender slot and reserve it. This must not fail due to
3014 * the prior check for free WAL senders in InitProcess().
3015 */
3016 for (i = 0; i < max_wal_senders; i++)
3017 {
3018 WalSnd *walsnd = &WalSndCtl->walsnds[i];
3019
3020 SpinLockAcquire(&walsnd->mutex);
3021
3022 if (walsnd->pid != 0)
3023 {
3024 SpinLockRelease(&walsnd->mutex);
3025 continue;
3026 }
3027 else
3028 {
3029 /*
3030 * Found a free slot. Reserve it for us.
3031 */
3032 walsnd->pid = MyProcPid;
3033 walsnd->state = WALSNDSTATE_STARTUP;
3034 walsnd->sentPtr = InvalidXLogRecPtr;
3035 walsnd->needreload = false;
3036 walsnd->write = InvalidXLogRecPtr;
3037 walsnd->flush = InvalidXLogRecPtr;
3038 walsnd->apply = InvalidXLogRecPtr;
3039 walsnd->writeLag = -1;
3040 walsnd->flushLag = -1;
3041 walsnd->applyLag = -1;
3042 walsnd->sync_standby_priority = 0;
3043 walsnd->replyTime = 0;
3044
3045 /*
3046 * The kind assignment is done here and not in StartReplication()
3047 * and StartLogicalReplication(). Indeed, the logical walsender
3048 * needs to read WAL records (like snapshot of running
3049 * transactions) during the slot creation. So it needs to be woken
3050 * up based on its kind.
3051 *
3052 * The kind assignment could also be done in StartReplication(),
3053 * StartLogicalReplication() and CREATE_REPLICATION_SLOT but it
3054 * seems better to set it on one place.
3055 */
3056 if (MyDatabaseId == InvalidOid)
3058 else
3060
3061 SpinLockRelease(&walsnd->mutex);
3062 /* don't need the lock anymore */
3063 MyWalSnd = (WalSnd *) walsnd;
3064
3065 break;
3066 }
3067 }
3068
3069 Assert(MyWalSnd != NULL);
3070
3071 /* Arrange to clean up at walsender exit */
3073}
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
int i
Definition: isn.c:77
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
WalSnd walsnds[FLEXIBLE_ARRAY_MEMBER]
TimeOffset writeLag
slock_t mutex
XLogRecPtr flush
XLogRecPtr sentPtr
TimeOffset flushLag
ReplicationKind kind
XLogRecPtr write
TimeOffset applyLag
int sync_standby_priority
bool needreload
TimestampTz replyTime
XLogRecPtr apply
int max_wal_senders
Definition: walsender.c:129
static void WalSndKill(int code, Datum arg)
Definition: walsender.c:3077
WalSndCtlData * WalSndCtl
Definition: walsender.c:117
@ WALSNDSTATE_STARTUP

References WalSnd::apply, WalSnd::applyLag, Assert(), WalSnd::flush, WalSnd::flushLag, i, InvalidOid, InvalidXLogRecPtr, WalSnd::kind, max_wal_senders, WalSnd::mutex, MyDatabaseId, MyProcPid, MyWalSnd, WalSnd::needreload, on_shmem_exit(), WalSnd::pid, REPLICATION_KIND_LOGICAL, REPLICATION_KIND_PHYSICAL, WalSnd::replyTime, WalSnd::sentPtr, SpinLockAcquire, SpinLockRelease, WalSnd::state, WalSnd::sync_standby_priority, WalSndCtl, WalSndKill(), WalSndCtlData::walsnds, WALSNDSTATE_STARTUP, WalSnd::write, and WalSnd::writeLag.

Referenced by InitWalSender().

◆ LagTrackerRead()

static TimeOffset LagTrackerRead ( int  head,
XLogRecPtr  lsn,
TimestampTz  now 
)
static

Definition at line 4273 of file walsender.c.

4274{
4275 TimestampTz time = 0;
4276
4277 /* Read all unread samples up to this LSN or end of buffer. */
4278 while (lag_tracker->read_heads[head] != lag_tracker->write_head &&
4280 {
4282 lag_tracker->last_read[head] =
4284 lag_tracker->read_heads[head] =
4286 }
4287
4288 /*
4289 * If the lag tracker is empty, that means the standby has processed
4290 * everything we've ever sent so we should now clear 'last_read'. If we
4291 * didn't do that, we'd risk using a stale and irrelevant sample for
4292 * interpolation at the beginning of the next burst of WAL after a period
4293 * of idleness.
4294 */
4296 lag_tracker->last_read[head].time = 0;
4297
4298 if (time > now)
4299 {
4300 /* If the clock somehow went backwards, treat as not found. */
4301 return -1;
4302 }
4303 else if (time == 0)
4304 {
4305 /*
4306 * We didn't cross a time. If there is a future sample that we
4307 * haven't reached yet, and we've already reached at least one sample,
4308 * let's interpolate the local flushed time. This is mainly useful
4309 * for reporting a completely stuck apply position as having
4310 * increasing lag, since otherwise we'd have to wait for it to
4311 * eventually start moving again and cross one of our samples before
4312 * we can show the lag increasing.
4313 */
4315 {
4316 /* There are no future samples, so we can't interpolate. */
4317 return -1;
4318 }
4319 else if (lag_tracker->last_read[head].time != 0)
4320 {
4321 /* We can interpolate between last_read and the next sample. */
4322 double fraction;
4323 WalTimeSample prev = lag_tracker->last_read[head];
4325
4326 if (lsn < prev.lsn)
4327 {
4328 /*
4329 * Reported LSNs shouldn't normally go backwards, but it's
4330 * possible when there is a timeline change. Treat as not
4331 * found.
4332 */
4333 return -1;
4334 }
4335
4336 Assert(prev.lsn < next.lsn);
4337
4338 if (prev.time > next.time)
4339 {
4340 /* If the clock somehow went backwards, treat as not found. */
4341 return -1;
4342 }
4343
4344 /* See how far we are between the previous and next samples. */
4345 fraction =
4346 (double) (lsn - prev.lsn) / (double) (next.lsn - prev.lsn);
4347
4348 /* Scale the local flush time proportionally. */
4349 time = (TimestampTz)
4350 ((double) prev.time + (next.time - prev.time) * fraction);
4351 }
4352 else
4353 {
4354 /*
4355 * We have only a future sample, implying that we were entirely
4356 * caught up but and now there is a new burst of WAL and the
4357 * standby hasn't processed the first sample yet. Until the
4358 * standby reaches the future sample the best we can do is report
4359 * the hypothetical lag if that sample were to be replayed now.
4360 */
4362 }
4363 }
4364
4365 /* Return the elapsed time since local flush time in microseconds. */
4366 Assert(time != 0);
4367 return now - time;
4368}
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1609
static int32 next
Definition: blutils.c:224
int64 TimestampTz
Definition: timestamp.h:39
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:232
int read_heads[NUM_SYNC_REP_WAIT_MODE]
Definition: walsender.c:234
WalTimeSample last_read[NUM_SYNC_REP_WAIT_MODE]
Definition: walsender.c:235
int write_head
Definition: walsender.c:233
TimestampTz time
Definition: walsender.c:222
XLogRecPtr lsn
Definition: walsender.c:221
#define LAG_TRACKER_BUFFER_SIZE
Definition: walsender.c:226

References Assert(), LagTracker::buffer, lag_tracker, LAG_TRACKER_BUFFER_SIZE, LagTracker::last_read, WalTimeSample::lsn, next, now(), LagTracker::read_heads, WalTimeSample::time, and LagTracker::write_head.

Referenced by ProcessStandbyReplyMessage().

◆ LagTrackerWrite()

static void LagTrackerWrite ( XLogRecPtr  lsn,
TimestampTz  local_flush_time 
)
static

Definition at line 4208 of file walsender.c.

4209{
4210 bool buffer_full;
4211 int new_write_head;
4212 int i;
4213
4214 if (!am_walsender)
4215 return;
4216
4217 /*
4218 * If the lsn hasn't advanced since last time, then do nothing. This way
4219 * we only record a new sample when new WAL has been written.
4220 */
4221 if (lag_tracker->last_lsn == lsn)
4222 return;
4223 lag_tracker->last_lsn = lsn;
4224
4225 /*
4226 * If advancing the write head of the circular buffer would crash into any
4227 * of the read heads, then the buffer is full. In other words, the
4228 * slowest reader (presumably apply) is the one that controls the release
4229 * of space.
4230 */
4231 new_write_head = (lag_tracker->write_head + 1) % LAG_TRACKER_BUFFER_SIZE;
4232 buffer_full = false;
4233 for (i = 0; i < NUM_SYNC_REP_WAIT_MODE; ++i)
4234 {
4235 if (new_write_head == lag_tracker->read_heads[i])
4236 buffer_full = true;
4237 }
4238
4239 /*
4240 * If the buffer is full, for now we just rewind by one slot and overwrite
4241 * the last sample, as a simple (if somewhat uneven) way to lower the
4242 * sampling rate. There may be better adaptive compaction algorithms.
4243 */
4244 if (buffer_full)
4245 {
4246 new_write_head = lag_tracker->write_head;
4247 if (lag_tracker->write_head > 0)
4249 else
4251 }
4252
4253 /* Store a sample at the current write head position. */
4255 lag_tracker->buffer[lag_tracker->write_head].time = local_flush_time;
4256 lag_tracker->write_head = new_write_head;
4257}
XLogRecPtr last_lsn
Definition: walsender.c:231
#define NUM_SYNC_REP_WAIT_MODE
Definition: syncrep.h:27

References am_walsender, LagTracker::buffer, i, lag_tracker, LAG_TRACKER_BUFFER_SIZE, LagTracker::last_lsn, WalTimeSample::lsn, NUM_SYNC_REP_WAIT_MODE, LagTracker::read_heads, WalTimeSample::time, and LagTracker::write_head.

Referenced by WalSndUpdateProgress(), and XLogSendPhysical().

◆ logical_read_xlog_page()

static int logical_read_xlog_page ( XLogReaderState state,
XLogRecPtr  targetPagePtr,
int  reqLen,
XLogRecPtr  targetRecPtr,
char *  cur_page 
)
static

Definition at line 1031 of file walsender.c.

1033{
1034 XLogRecPtr flushptr;
1035 int count;
1036 WALReadError errinfo;
1037 XLogSegNo segno;
1038 TimeLineID currTLI;
1039
1040 /*
1041 * Make sure we have enough WAL available before retrieving the current
1042 * timeline.
1043 */
1044 flushptr = WalSndWaitForWal(targetPagePtr + reqLen);
1045
1046 /* Fail if not enough (implies we are going to shut down) */
1047 if (flushptr < targetPagePtr + reqLen)
1048 return -1;
1049
1050 /*
1051 * Since logical decoding is also permitted on a standby server, we need
1052 * to check if the server is in recovery to decide how to get the current
1053 * timeline ID (so that it also covers the promotion or timeline change
1054 * cases). We must determine am_cascading_walsender after waiting for the
1055 * required WAL so that it is correct when the walsender wakes up after a
1056 * promotion.
1057 */
1059
1061 GetXLogReplayRecPtr(&currTLI);
1062 else
1063 currTLI = GetWALInsertionTimeLine();
1064
1065 XLogReadDetermineTimeline(state, targetPagePtr, reqLen, currTLI);
1066 sendTimeLineIsHistoric = (state->currTLI != currTLI);
1067 sendTimeLine = state->currTLI;
1068 sendTimeLineValidUpto = state->currTLIValidUntil;
1069 sendTimeLineNextTLI = state->nextTLI;
1070
1071 if (targetPagePtr + XLOG_BLCKSZ <= flushptr)
1072 count = XLOG_BLCKSZ; /* more than one block available */
1073 else
1074 count = flushptr - targetPagePtr; /* part of the page available */
1075
1076 /* now actually read the data, we know it's there */
1077 if (!WALRead(state,
1078 cur_page,
1079 targetPagePtr,
1080 count,
1081 currTLI, /* Pass the current TLI because only
1082 * WalSndSegmentOpen controls whether new TLI
1083 * is needed. */
1084 &errinfo))
1085 WALReadRaiseError(&errinfo);
1086
1087 /*
1088 * After reading into the buffer, check that what we read was valid. We do
1089 * this after reading, because even though the segment was present when we
1090 * opened it, it might get recycled or removed while we read it. The
1091 * read() succeeds in that case, but the data we tried to read might
1092 * already have been overwritten with new WAL records.
1093 */
1094 XLByteToSeg(targetPagePtr, segno, state->segcxt.ws_segsize);
1095 CheckXLogRemoved(segno, state->seg.ws_tli);
1096
1097 return count;
1098}
Definition: regguts.h:323
static TimeLineID sendTimeLine
Definition: walsender.c:164
static bool sendTimeLineIsHistoric
Definition: walsender.c:166
static XLogRecPtr WalSndWaitForWal(XLogRecPtr loc)
Definition: walsender.c:1803
static TimeLineID sendTimeLineNextTLI
Definition: walsender.c:165
static XLogRecPtr sendTimeLineValidUpto
Definition: walsender.c:167
TimeLineID GetWALInsertionTimeLine(void)
Definition: xlog.c:6572
void CheckXLogRemoved(XLogSegNo segno, TimeLineID tli)
Definition: xlog.c:3743
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes)
uint64 XLogSegNo
Definition: xlogdefs.h:51
bool WALRead(XLogReaderState *state, char *buf, XLogRecPtr startptr, Size count, TimeLineID tli, WALReadError *errinfo)
Definition: xlogreader.c:1514
void XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wantLength, TimeLineID currTLI)
Definition: xlogutils.c:707
void WALReadRaiseError(WALReadError *errinfo)
Definition: xlogutils.c:1011

References am_cascading_walsender, CheckXLogRemoved(), GetWALInsertionTimeLine(), GetXLogReplayRecPtr(), RecoveryInProgress(), sendTimeLine, sendTimeLineIsHistoric, sendTimeLineNextTLI, sendTimeLineValidUpto, WALRead(), WALReadRaiseError(), WalSndWaitForWal(), XLByteToSeg, and XLogReadDetermineTimeline().

Referenced by CreateReplicationSlot(), and StartLogicalReplication().

◆ NeedToWaitForStandbys()

static bool NeedToWaitForStandbys ( XLogRecPtr  flushed_lsn,
uint32 wait_event 
)
static

Definition at line 1743 of file walsender.c.

1744{
1745 int elevel = got_STOPPING ? ERROR : WARNING;
1746 bool failover_slot;
1747
1748 failover_slot = (replication_active && MyReplicationSlot->data.failover);
1749
1750 /*
1751 * Note that after receiving the shutdown signal, an ERROR is reported if
1752 * any slots are dropped, invalidated, or inactive. This measure is taken
1753 * to prevent the walsender from waiting indefinitely.
1754 */
1755 if (failover_slot && !StandbySlotsHaveCaughtup(flushed_lsn, elevel))
1756 {
1757 *wait_event = WAIT_EVENT_WAIT_FOR_STANDBY_CONFIRMATION;
1758 return true;
1759 }
1760
1761 *wait_event = 0;
1762 return false;
1763}
#define WARNING
Definition: elog.h:36
bool StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
Definition: slot.c:2905

References ReplicationSlot::data, ERROR, ReplicationSlotPersistentData::failover, got_STOPPING, MyReplicationSlot, replication_active, StandbySlotsHaveCaughtup(), and WARNING.

Referenced by NeedToWaitForWal(), and WalSndWaitForWal().

◆ NeedToWaitForWal()

static bool NeedToWaitForWal ( XLogRecPtr  target_lsn,
XLogRecPtr  flushed_lsn,
uint32 wait_event 
)
static

Definition at line 1775 of file walsender.c.

1777{
1778 /* Check if we need to wait for WALs to be flushed to disk */
1779 if (target_lsn > flushed_lsn)
1780 {
1781 *wait_event = WAIT_EVENT_WAL_SENDER_WAIT_FOR_WAL;
1782 return true;
1783 }
1784
1785 /* Check if the standby slots have caught up to the flushed position */
1786 return NeedToWaitForStandbys(flushed_lsn, wait_event);
1787}
static bool NeedToWaitForStandbys(XLogRecPtr flushed_lsn, uint32 *wait_event)
Definition: walsender.c:1743

References NeedToWaitForStandbys().

Referenced by WalSndWaitForWal().

◆ offset_to_interval()

static Interval * offset_to_interval ( TimeOffset  offset)
static

Definition at line 3960 of file walsender.c.

3961{
3962 Interval *result = palloc(sizeof(Interval));
3963
3964 result->month = 0;
3965 result->day = 0;
3966 result->time = offset;
3967
3968 return result;
3969}
void * palloc(Size size)
Definition: mcxt.c:1365
int32 day
Definition: timestamp.h:51
int32 month
Definition: timestamp.h:52
TimeOffset time
Definition: timestamp.h:49

References Interval::day, Interval::month, palloc(), and Interval::time.

Referenced by pg_stat_get_wal_senders().

◆ parseCreateReplSlotOptions()

static void parseCreateReplSlotOptions ( CreateReplicationSlotCmd cmd,
bool *  reserve_wal,
CRSSnapshotAction snapshot_action,
bool *  two_phase,
bool *  failover 
)
static

Definition at line 1104 of file walsender.c.

1108{
1109 ListCell *lc;
1110 bool snapshot_action_given = false;
1111 bool reserve_wal_given = false;
1112 bool two_phase_given = false;
1113 bool failover_given = false;
1114
1115 /* Parse options */
1116 foreach(lc, cmd->options)
1117 {
1118 DefElem *defel = (DefElem *) lfirst(lc);
1119
1120 if (strcmp(defel->defname, "snapshot") == 0)
1121 {
1122 char *action;
1123
1124 if (snapshot_action_given || cmd->kind != REPLICATION_KIND_LOGICAL)
1125 ereport(ERROR,
1126 (errcode(ERRCODE_SYNTAX_ERROR),
1127 errmsg("conflicting or redundant options")));
1128
1129 action = defGetString(defel);
1130 snapshot_action_given = true;
1131
1132 if (strcmp(action, "export") == 0)
1133 *snapshot_action = CRS_EXPORT_SNAPSHOT;
1134 else if (strcmp(action, "nothing") == 0)
1135 *snapshot_action = CRS_NOEXPORT_SNAPSHOT;
1136 else if (strcmp(action, "use") == 0)
1137 *snapshot_action = CRS_USE_SNAPSHOT;
1138 else
1139 ereport(ERROR,
1140 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1141 errmsg("unrecognized value for CREATE_REPLICATION_SLOT option \"%s\": \"%s\"",
1142 defel->defname, action)));
1143 }
1144 else if (strcmp(defel->defname, "reserve_wal") == 0)
1145 {
1146 if (reserve_wal_given || cmd->kind != REPLICATION_KIND_PHYSICAL)
1147 ereport(ERROR,
1148 (errcode(ERRCODE_SYNTAX_ERROR),
1149 errmsg("conflicting or redundant options")));
1150
1151 reserve_wal_given = true;
1152 *reserve_wal = defGetBoolean(defel);
1153 }
1154 else if (strcmp(defel->defname, "two_phase") == 0)
1155 {
1156 if (two_phase_given || cmd->kind != REPLICATION_KIND_LOGICAL)
1157 ereport(ERROR,
1158 (errcode(ERRCODE_SYNTAX_ERROR),
1159 errmsg("conflicting or redundant options")));
1160 two_phase_given = true;
1161 *two_phase = defGetBoolean(defel);
1162 }
1163 else if (strcmp(defel->defname, "failover") == 0)
1164 {
1165 if (failover_given || cmd->kind != REPLICATION_KIND_LOGICAL)
1166 ereport(ERROR,
1167 (errcode(ERRCODE_SYNTAX_ERROR),
1168 errmsg("conflicting or redundant options")));
1169 failover_given = true;
1170 *failover = defGetBoolean(defel);
1171 }
1172 else
1173 elog(ERROR, "unrecognized option: %s", defel->defname);
1174 }
1175}
char * defGetString(DefElem *def)
Definition: define.c:35
#define lfirst(lc)
Definition: pg_list.h:172
char * defname
Definition: parsenodes.h:842
@ CRS_NOEXPORT_SNAPSHOT
Definition: walsender.h:23

References generate_unaccent_rules::action, CRS_EXPORT_SNAPSHOT, CRS_NOEXPORT_SNAPSHOT, CRS_USE_SNAPSHOT, defGetBoolean(), defGetString(), DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, failover, CreateReplicationSlotCmd::kind, lfirst, CreateReplicationSlotCmd::options, REPLICATION_KIND_LOGICAL, REPLICATION_KIND_PHYSICAL, and two_phase.

Referenced by CreateReplicationSlot().

◆ pg_stat_get_wal_senders()

Datum pg_stat_get_wal_senders ( PG_FUNCTION_ARGS  )

Definition at line 3976 of file walsender.c.

3977{
3978#define PG_STAT_GET_WAL_SENDERS_COLS 12
3979 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
3980 SyncRepStandbyData *sync_standbys;
3981 int num_standbys;
3982 int i;
3983
3984 InitMaterializedSRF(fcinfo, 0);
3985
3986 /*
3987 * Get the currently active synchronous standbys. This could be out of
3988 * date before we're done, but we'll use the data anyway.
3989 */
3990 num_standbys = SyncRepGetCandidateStandbys(&sync_standbys);
3991
3992 for (i = 0; i < max_wal_senders; i++)
3993 {
3994 WalSnd *walsnd = &WalSndCtl->walsnds[i];
3995 XLogRecPtr sent_ptr;
3997 XLogRecPtr flush;
3998 XLogRecPtr apply;
3999 TimeOffset writeLag;
4000 TimeOffset flushLag;
4001 TimeOffset applyLag;
4002 int priority;
4003 int pid;
4005 TimestampTz replyTime;
4006 bool is_sync_standby;
4008 bool nulls[PG_STAT_GET_WAL_SENDERS_COLS] = {0};
4009 int j;
4010
4011 /* Collect data from shared memory */
4012 SpinLockAcquire(&walsnd->mutex);
4013 if (walsnd->pid == 0)
4014 {
4015 SpinLockRelease(&walsnd->mutex);
4016 continue;
4017 }
4018 pid = walsnd->pid;
4019 sent_ptr = walsnd->sentPtr;
4020 state = walsnd->state;
4021 write = walsnd->write;
4022 flush = walsnd->flush;
4023 apply = walsnd->apply;
4024 writeLag = walsnd->writeLag;
4025 flushLag = walsnd->flushLag;
4026 applyLag = walsnd->applyLag;
4027 priority = walsnd->sync_standby_priority;
4028 replyTime = walsnd->replyTime;
4029 SpinLockRelease(&walsnd->mutex);
4030
4031 /*
4032 * Detect whether walsender is/was considered synchronous. We can
4033 * provide some protection against stale data by checking the PID
4034 * along with walsnd_index.
4035 */
4036 is_sync_standby = false;
4037 for (j = 0; j < num_standbys; j++)
4038 {
4039 if (sync_standbys[j].walsnd_index == i &&
4040 sync_standbys[j].pid == pid)
4041 {
4042 is_sync_standby = true;
4043 break;
4044 }
4045 }
4046
4047 values[0] = Int32GetDatum(pid);
4048
4049 if (!has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS))
4050 {
4051 /*
4052 * Only superusers and roles with privileges of pg_read_all_stats
4053 * can see details. Other users only get the pid value to know
4054 * it's a walsender, but no details.
4055 */
4056 MemSet(&nulls[1], true, PG_STAT_GET_WAL_SENDERS_COLS - 1);
4057 }
4058 else
4059 {
4061
4062 if (XLogRecPtrIsInvalid(sent_ptr))
4063 nulls[2] = true;
4064 values[2] = LSNGetDatum(sent_ptr);
4065
4067 nulls[3] = true;
4068 values[3] = LSNGetDatum(write);
4069
4070 if (XLogRecPtrIsInvalid(flush))
4071 nulls[4] = true;
4072 values[4] = LSNGetDatum(flush);
4073
4074 if (XLogRecPtrIsInvalid(apply))
4075 nulls[5] = true;
4076 values[5] = LSNGetDatum(apply);
4077
4078 /*
4079 * Treat a standby such as a pg_basebackup background process
4080 * which always returns an invalid flush location, as an
4081 * asynchronous standby.
4082 */
4083 priority = XLogRecPtrIsInvalid(flush) ? 0 : priority;
4084
4085 if (writeLag < 0)
4086 nulls[6] = true;
4087 else
4089
4090 if (flushLag < 0)
4091 nulls[7] = true;
4092 else
4094
4095 if (applyLag < 0)
4096 nulls[8] = true;
4097 else
4099
4100 values[9] = Int32GetDatum(priority);
4101
4102 /*
4103 * More easily understood version of standby state. This is purely
4104 * informational.
4105 *
4106 * In quorum-based sync replication, the role of each standby
4107 * listed in synchronous_standby_names can be changing very
4108 * frequently. Any standbys considered as "sync" at one moment can
4109 * be switched to "potential" ones at the next moment. So, it's
4110 * basically useless to report "sync" or "potential" as their sync
4111 * states. We report just "quorum" for them.
4112 */
4113 if (priority == 0)
4114 values[10] = CStringGetTextDatum("async");
4115 else if (is_sync_standby)
4117 CStringGetTextDatum("sync") : CStringGetTextDatum("quorum");
4118 else
4119 values[10] = CStringGetTextDatum("potential");
4120
4121 if (replyTime == 0)
4122 nulls[11] = true;
4123 else
4124 values[11] = TimestampTzGetDatum(replyTime);
4125 }
4126
4127 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
4128 values, nulls);
4129 }
4130
4131 return (Datum) 0;
4132}
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5284
#define MemSet(start, val, len)
Definition: c.h:1019
int64 TimeOffset
Definition: timestamp.h:40
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
#define write(a, b, c)
Definition: win32.h:14
int j
Definition: isn.c:78
Oid GetUserId(void)
Definition: miscinit.c:469
static Datum LSNGetDatum(XLogRecPtr X)
Definition: pg_lsn.h:31
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222
TupleDesc setDesc
Definition: execnodes.h:364
Tuplestorestate * setResult
Definition: execnodes.h:363
uint8 syncrep_method
Definition: syncrep.h:68
SyncRepConfigData * SyncRepConfig
Definition: syncrep.c:97
int SyncRepGetCandidateStandbys(SyncRepStandbyData **standbys)
Definition: syncrep.c:754
#define SYNC_REP_PRIORITY
Definition: syncrep.h:35
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
static Datum TimestampTzGetDatum(TimestampTz X)
Definition: timestamp.h:52
static Datum IntervalPGetDatum(const Interval *X)
Definition: timestamp.h:58
#define PG_STAT_GET_WAL_SENDERS_COLS
static Interval * offset_to_interval(TimeOffset offset)
Definition: walsender.c:3960
static const char * WalSndGetStateString(WalSndState state)
Definition: walsender.c:3941
WalSndState
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29

References WalSnd::apply, WalSnd::applyLag, CStringGetTextDatum, WalSnd::flush, WalSnd::flushLag, GetUserId(), has_privs_of_role(), i, InitMaterializedSRF(), Int32GetDatum(), IntervalPGetDatum(), j, LSNGetDatum(), max_wal_senders, MemSet, WalSnd::mutex, offset_to_interval(), PG_STAT_GET_WAL_SENDERS_COLS, WalSnd::pid, WalSnd::replyTime, WalSnd::sentPtr, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SpinLockAcquire, SpinLockRelease, WalSnd::state, SYNC_REP_PRIORITY, WalSnd::sync_standby_priority, SyncRepConfigData::syncrep_method, SyncRepConfig, SyncRepGetCandidateStandbys(), TimestampTzGetDatum(), tuplestore_putvalues(), values, WalSndCtl, WalSndGetStateString(), WalSndCtlData::walsnds, WalSnd::write, write, WalSnd::writeLag, and XLogRecPtrIsInvalid.

◆ PhysicalConfirmReceivedLocation()

static void PhysicalConfirmReceivedLocation ( XLogRecPtr  lsn)
static

Definition at line 2381 of file walsender.c.

2382{
2383 bool changed = false;
2385
2386 Assert(lsn != InvalidXLogRecPtr);
2387 SpinLockAcquire(&slot->mutex);
2388 if (slot->data.restart_lsn != lsn)
2389 {
2390 changed = true;
2391 slot->data.restart_lsn = lsn;
2392 }
2393 SpinLockRelease(&slot->mutex);
2394
2395 if (changed)
2396 {
2400 }
2401
2402 /*
2403 * One could argue that the slot should be saved to disk now, but that'd
2404 * be energy wasted - the worst thing lost information could cause here is
2405 * to give wrong information in a statistics view - we'll just potentially
2406 * be more conservative in removing files.
2407 */
2408}
void ReplicationSlotsComputeRequiredLSN(void)
Definition: slot.c:1201
slock_t mutex
Definition: slot.h:165
void PhysicalWakeupLogicalWalSnd(void)
Definition: walsender.c:1718

References Assert(), ReplicationSlot::data, InvalidXLogRecPtr, ReplicationSlot::mutex, MyReplicationSlot, PhysicalWakeupLogicalWalSnd(), ReplicationSlotMarkDirty(), ReplicationSlotsComputeRequiredLSN(), ReplicationSlotPersistentData::restart_lsn, SpinLockAcquire, and SpinLockRelease.

Referenced by ProcessStandbyReplyMessage().

◆ PhysicalReplicationSlotNewXmin()

static void PhysicalReplicationSlotNewXmin ( TransactionId  feedbackXmin,
TransactionId  feedbackCatalogXmin 
)
static

Definition at line 2519 of file walsender.c.

2520{
2521 bool changed = false;
2523
2524 SpinLockAcquire(&slot->mutex);
2526
2527 /*
2528 * For physical replication we don't need the interlock provided by xmin
2529 * and effective_xmin since the consequences of a missed increase are
2530 * limited to query cancellations, so set both at once.
2531 */
2532 if (!TransactionIdIsNormal(slot->data.xmin) ||
2533 !TransactionIdIsNormal(feedbackXmin) ||
2534 TransactionIdPrecedes(slot->data.xmin, feedbackXmin))
2535 {
2536 changed = true;
2537 slot->data.xmin = feedbackXmin;
2538 slot->effective_xmin = feedbackXmin;
2539 }
2541 !TransactionIdIsNormal(feedbackCatalogXmin) ||
2542 TransactionIdPrecedes(slot->data.catalog_xmin, feedbackCatalogXmin))
2543 {
2544 changed = true;
2545 slot->data.catalog_xmin = feedbackCatalogXmin;
2546 slot->effective_catalog_xmin = feedbackCatalogXmin;
2547 }
2548 SpinLockRelease(&slot->mutex);
2549
2550 if (changed)
2551 {
2554 }
2555}
void ReplicationSlotsComputeRequiredXmin(bool already_locked)
Definition: slot.c:1145
TransactionId xmin
Definition: slot.h:96
TransactionId catalog_xmin
Definition: slot.h:104
TransactionId effective_catalog_xmin
Definition: slot.h:189
TransactionId effective_xmin
Definition: slot.h:188
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

References ReplicationSlotPersistentData::catalog_xmin, ReplicationSlot::data, ReplicationSlot::effective_catalog_xmin, ReplicationSlot::effective_xmin, InvalidTransactionId, ReplicationSlot::mutex, MyProc, MyReplicationSlot, ReplicationSlotMarkDirty(), ReplicationSlotsComputeRequiredXmin(), SpinLockAcquire, SpinLockRelease, TransactionIdIsNormal, TransactionIdPrecedes(), ReplicationSlotPersistentData::xmin, and PGPROC::xmin.

Referenced by ProcessStandbyHSFeedbackMessage().

◆ PhysicalWakeupLogicalWalSnd()

void PhysicalWakeupLogicalWalSnd ( void  )

Definition at line 1718 of file walsender.c.

1719{
1721
1722 /*
1723 * If we are running in a standby, there is no need to wake up walsenders.
1724 * This is because we do not support syncing slots to cascading standbys,
1725 * so, there are no walsenders waiting for standbys to catch up.
1726 */
1727 if (RecoveryInProgress())
1728 return;
1729
1732}
void ConditionVariableBroadcast(ConditionVariable *cv)
bool SlotExistsInSyncStandbySlots(const char *slot_name)
Definition: slot.c:2872
#define SlotIsPhysical(slot)
Definition: slot.h:254
ConditionVariable wal_confirm_rcv_cv

References Assert(), ConditionVariableBroadcast(), ReplicationSlot::data, MyReplicationSlot, ReplicationSlotPersistentData::name, NameStr, RecoveryInProgress(), SlotExistsInSyncStandbySlots(), SlotIsPhysical, WalSndCtlData::wal_confirm_rcv_cv, and WalSndCtl.

Referenced by pg_physical_replication_slot_advance(), and PhysicalConfirmReceivedLocation().

◆ ProcessPendingWrites()

static void ProcessPendingWrites ( void  )
static

Definition at line 1599 of file walsender.c.

1600{
1601 for (;;)
1602 {
1603 long sleeptime;
1604
1605 /* Check for input from the client */
1607
1608 /* die if timeout was reached */
1610
1611 /* Send keepalive if the time has come */
1613
1614 if (!pq_is_send_pending())
1615 break;
1616
1618
1619 /* Sleep until something happens or we time out */
1621 WAIT_EVENT_WAL_SENDER_WRITE_DATA);
1622
1623 /* Clear any already-pending wakeups */
1625
1627
1628 /* Process any requests or signals received recently */
1630 {
1631 ConfigReloadPending = false;
1634 }
1635
1636 /* Try to flush pending output to the client */
1637 if (pq_flush_if_writable() != 0)
1639 }
1640
1641 /* reactivate latch so WalSndLoop knows to continue */
1643}
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1645
struct Latch * MyLatch
Definition: globals.c:63
void ProcessConfigFile(GucContext context)
Definition: guc-file.l:120
@ PGC_SIGHUP
Definition: guc.h:75
volatile sig_atomic_t ConfigReloadPending
Definition: interrupt.c:27
void SetLatch(Latch *latch)
Definition: latch.c:290
void ResetLatch(Latch *latch)
Definition: latch.c:374
#define pq_flush_if_writable()
Definition: libpq.h:47
#define pq_is_send_pending()
Definition: libpq.h:48
void SyncRepInitConfig(void)
Definition: syncrep.c:445
#define WL_SOCKET_READABLE
Definition: waiteventset.h:35
#define WL_SOCKET_WRITEABLE
Definition: waiteventset.h:36
static void WalSndWait(uint32 socket_events, long timeout, uint32 wait_event)
Definition: walsender.c:3800
static void WalSndCheckTimeOut(void)
Definition: walsender.c:2832
static void ProcessRepliesIfAny(void)
Definition: walsender.c:2230
static void WalSndKeepaliveIfNecessary(void)
Definition: walsender.c:4170
static pg_noreturn void WalSndShutdown(void)
Definition: walsender.c:370
static long WalSndComputeSleeptime(TimestampTz now)
Definition: walsender.c:2788

References CHECK_FOR_INTERRUPTS, ConfigReloadPending, GetCurrentTimestamp(), MyLatch, PGC_SIGHUP, pq_flush_if_writable, pq_is_send_pending, ProcessConfigFile(), ProcessRepliesIfAny(), ResetLatch(), SetLatch(), SyncRepInitConfig(), WalSndCheckTimeOut(), WalSndComputeSleeptime(), WalSndKeepaliveIfNecessary(), WalSndShutdown(), WalSndWait(), WL_SOCKET_READABLE, and WL_SOCKET_WRITEABLE.

Referenced by WalSndUpdateProgress(), and WalSndWriteData().

◆ ProcessRepliesIfAny()

static void ProcessRepliesIfAny ( void  )
static

Definition at line 2230 of file walsender.c.

2231{
2232 unsigned char firstchar;
2233 int maxmsglen;
2234 int r;
2235 bool received = false;
2236
2238
2239 /*
2240 * If we already received a CopyDone from the frontend, any subsequent
2241 * message is the beginning of a new command, and should be processed in
2242 * the main processing loop.
2243 */
2244 while (!streamingDoneReceiving)
2245 {
2247 r = pq_getbyte_if_available(&firstchar);
2248 if (r < 0)
2249 {
2250 /* unexpected error or EOF */
2252 (errcode(ERRCODE_PROTOCOL_VIOLATION),
2253 errmsg("unexpected EOF on standby connection")));
2254 proc_exit(0);
2255 }
2256 if (r == 0)
2257 {
2258 /* no data available without blocking */
2259 pq_endmsgread();
2260 break;
2261 }
2262
2263 /* Validate message type and set packet size limit */
2264 switch (firstchar)
2265 {
2266 case PqMsg_CopyData:
2267 maxmsglen = PQ_LARGE_MESSAGE_LIMIT;
2268 break;
2269 case PqMsg_CopyDone:
2270 case PqMsg_Terminate:
2271 maxmsglen = PQ_SMALL_MESSAGE_LIMIT;
2272 break;
2273 default:
2274 ereport(FATAL,
2275 (errcode(ERRCODE_PROTOCOL_VIOLATION),
2276 errmsg("invalid standby message type \"%c\"",
2277 firstchar)));
2278 maxmsglen = 0; /* keep compiler quiet */
2279 break;
2280 }
2281
2282 /* Read the message contents */
2284 if (pq_getmessage(&reply_message, maxmsglen))
2285 {
2287 (errcode(ERRCODE_PROTOCOL_VIOLATION),
2288 errmsg("unexpected EOF on standby connection")));
2289 proc_exit(0);
2290 }
2291
2292 /* ... and process it */
2293 switch (firstchar)
2294 {
2295 /*
2296 * PqMsg_CopyData means a standby reply wrapped in a CopyData
2297 * packet.
2298 */
2299 case PqMsg_CopyData:
2301 received = true;
2302 break;
2303
2304 /*
2305 * PqMsg_CopyDone means the standby requested to finish
2306 * streaming. Reply with CopyDone, if we had not sent that
2307 * already.
2308 */
2309 case PqMsg_CopyDone:
2311 {
2313 streamingDoneSending = true;
2314 }
2315
2317 received = true;
2318 break;
2319
2320 /*
2321 * PqMsg_Terminate means that the standby is closing down the
2322 * socket.
2323 */
2324 case PqMsg_Terminate:
2325 proc_exit(0);
2326
2327 default:
2328 Assert(false); /* NOT REACHED */
2329 }
2330 }
2331
2332 /*
2333 * Save the last reply timestamp if we've received at least one reply.
2334 */
2335 if (received)
2336 {
2339 }
2340}
#define COMMERROR
Definition: elog.h:33
#define FATAL
Definition: elog.h:41
void proc_exit(int code)
Definition: ipc.c:104
#define pq_putmessage_noblock(msgtype, s, len)
Definition: libpq.h:51
int pq_getbyte_if_available(unsigned char *c)
Definition: pqcomm.c:1003
void pq_endmsgread(void)
Definition: pqcomm.c:1165
#define PqMsg_Terminate
Definition: protocol.h:28
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:126
static bool waiting_for_ping_response
Definition: walsender.c:190
static TimestampTz last_processing
Definition: walsender.c:181
static bool streamingDoneSending
Definition: walsender.c:198
static void ProcessStandbyMessage(void)
Definition: walsender.c:2346
static bool streamingDoneReceiving
Definition: walsender.c:199

References Assert(), COMMERROR, ereport, errcode(), errmsg(), FATAL, GetCurrentTimestamp(), last_processing, last_reply_timestamp, pq_endmsgread(), pq_getbyte_if_available(), pq_getmessage(), PQ_LARGE_MESSAGE_LIMIT, pq_putmessage_noblock, PQ_SMALL_MESSAGE_LIMIT, pq_startmsgread(), PqMsg_CopyData, PqMsg_CopyDone, PqMsg_Terminate, proc_exit(), ProcessStandbyMessage(), reply_message, resetStringInfo(), streamingDoneReceiving, streamingDoneSending, and waiting_for_ping_response.

Referenced by ProcessPendingWrites(), WalSndLoop(), and WalSndWaitForWal().

◆ ProcessStandbyHSFeedbackMessage()

static void ProcessStandbyHSFeedbackMessage ( void  )
static

Definition at line 2599 of file walsender.c.

2600{
2601 TransactionId feedbackXmin;
2602 uint32 feedbackEpoch;
2603 TransactionId feedbackCatalogXmin;
2604 uint32 feedbackCatalogEpoch;
2605 TimestampTz replyTime;
2606
2607 /*
2608 * Decipher the reply message. The caller already consumed the msgtype
2609 * byte. See XLogWalRcvSendHSFeedback() in walreceiver.c for the creation
2610 * of this message.
2611 */
2612 replyTime = pq_getmsgint64(&reply_message);
2613 feedbackXmin = pq_getmsgint(&reply_message, 4);
2614 feedbackEpoch = pq_getmsgint(&reply_message, 4);
2615 feedbackCatalogXmin = pq_getmsgint(&reply_message, 4);
2616 feedbackCatalogEpoch = pq_getmsgint(&reply_message, 4);
2617
2619 {
2620 char *replyTimeStr;
2621
2622 /* Copy because timestamptz_to_str returns a static buffer */
2623 replyTimeStr = pstrdup(timestamptz_to_str(replyTime));
2624
2625 elog(DEBUG2, "hot standby feedback xmin %u epoch %u, catalog_xmin %u epoch %u reply_time %s",
2626 feedbackXmin,
2627 feedbackEpoch,
2628 feedbackCatalogXmin,
2629 feedbackCatalogEpoch,
2630 replyTimeStr);
2631
2632 pfree(replyTimeStr);
2633 }
2634
2635 /*
2636 * Update shared state for this WalSender process based on reply data from
2637 * standby.
2638 */
2639 {
2640 WalSnd *walsnd = MyWalSnd;
2641
2642 SpinLockAcquire(&walsnd->mutex);
2643 walsnd->replyTime = replyTime;
2644 SpinLockRelease(&walsnd->mutex);
2645 }
2646
2647 /*
2648 * Unset WalSender's xmins if the feedback message values are invalid.
2649 * This happens when the downstream turned hot_standby_feedback off.
2650 */
2651 if (!TransactionIdIsNormal(feedbackXmin)
2652 && !TransactionIdIsNormal(feedbackCatalogXmin))
2653 {
2655 if (MyReplicationSlot != NULL)
2656 PhysicalReplicationSlotNewXmin(feedbackXmin, feedbackCatalogXmin);
2657 return;
2658 }
2659
2660 /*
2661 * Check that the provided xmin/epoch are sane, that is, not in the future
2662 * and not so far back as to be already wrapped around. Ignore if not.
2663 */
2664 if (TransactionIdIsNormal(feedbackXmin) &&
2665 !TransactionIdInRecentPast(feedbackXmin, feedbackEpoch))
2666 return;
2667
2668 if (TransactionIdIsNormal(feedbackCatalogXmin) &&
2669 !TransactionIdInRecentPast(feedbackCatalogXmin, feedbackCatalogEpoch))
2670 return;
2671
2672 /*
2673 * Set the WalSender's xmin equal to the standby's requested xmin, so that
2674 * the xmin will be taken into account by GetSnapshotData() /
2675 * ComputeXidHorizons(). This will hold back the removal of dead rows and
2676 * thereby prevent the generation of cleanup conflicts on the standby
2677 * server.
2678 *
2679 * There is a small window for a race condition here: although we just
2680 * checked that feedbackXmin precedes nextXid, the nextXid could have
2681 * gotten advanced between our fetching it and applying the xmin below,
2682 * perhaps far enough to make feedbackXmin wrap around. In that case the
2683 * xmin we set here would be "in the future" and have no effect. No point
2684 * in worrying about this since it's too late to save the desired data
2685 * anyway. Assuming that the standby sends us an increasing sequence of
2686 * xmins, this could only happen during the first reply cycle, else our
2687 * own xmin would prevent nextXid from advancing so far.
2688 *
2689 * We don't bother taking the ProcArrayLock here. Setting the xmin field
2690 * is assumed atomic, and there's no real need to prevent concurrent
2691 * horizon determinations. (If we're moving our xmin forward, this is
2692 * obviously safe, and if we're moving it backwards, well, the data is at
2693 * risk already since a VACUUM could already have determined the horizon.)
2694 *
2695 * If we're using a replication slot we reserve the xmin via that,
2696 * otherwise via the walsender's PGPROC entry. We can only track the
2697 * catalog xmin separately when using a slot, so we store the least of the
2698 * two provided when not using a slot.
2699 *
2700 * XXX: It might make sense to generalize the ephemeral slot concept and
2701 * always use the slot mechanism to handle the feedback xmin.
2702 */
2703 if (MyReplicationSlot != NULL) /* XXX: persistency configurable? */
2704 PhysicalReplicationSlotNewXmin(feedbackXmin, feedbackCatalogXmin);
2705 else
2706 {
2707 if (TransactionIdIsNormal(feedbackCatalogXmin)
2708 && TransactionIdPrecedes(feedbackCatalogXmin, feedbackXmin))
2709 MyProc->xmin = feedbackCatalogXmin;
2710 else
2711 MyProc->xmin = feedbackXmin;
2712 }
2713}
const char * timestamptz_to_str(TimestampTz t)
Definition: timestamp.c:1862
uint32_t uint32
Definition: c.h:538
uint32 TransactionId
Definition: c.h:657
bool message_level_is_interesting(int elevel)
Definition: elog.c:273
#define DEBUG2
Definition: elog.h:29
char * pstrdup(const char *in)
Definition: mcxt.c:1759
void pfree(void *pointer)
Definition: mcxt.c:1594
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
int64 pq_getmsgint64(StringInfo msg)
Definition: pqformat.c:453
static void PhysicalReplicationSlotNewXmin(TransactionId feedbackXmin, TransactionId feedbackCatalogXmin)
Definition: walsender.c:2519
static bool TransactionIdInRecentPast(TransactionId xid, uint32 epoch)
Definition: walsender.c:2568

References DEBUG2, elog, InvalidTransactionId, message_level_is_interesting(), WalSnd::mutex, MyProc, MyReplicationSlot, MyWalSnd, pfree(), PhysicalReplicationSlotNewXmin(), pq_getmsgint(), pq_getmsgint64(), pstrdup(), reply_message, WalSnd::replyTime, SpinLockAcquire, SpinLockRelease, timestamptz_to_str(), TransactionIdInRecentPast(), TransactionIdIsNormal, TransactionIdPrecedes(), and PGPROC::xmin.

Referenced by ProcessStandbyMessage().

◆ ProcessStandbyMessage()

static void ProcessStandbyMessage ( void  )
static

Definition at line 2346 of file walsender.c.

2347{
2348 char msgtype;
2349
2350 /*
2351 * Check message type from the first byte.
2352 */
2353 msgtype = pq_getmsgbyte(&reply_message);
2354
2355 switch (msgtype)
2356 {
2359 break;
2360
2363 break;
2364
2367 break;
2368
2369 default:
2371 (errcode(ERRCODE_PROTOCOL_VIOLATION),
2372 errmsg("unexpected message type \"%c\"", msgtype)));
2373 proc_exit(0);
2374 }
2375}
int pq_getmsgbyte(StringInfo msg)
Definition: pqformat.c:399
#define PqReplMsg_PrimaryStatusRequest
Definition: protocol.h:83
#define PqReplMsg_HotStandbyFeedback
Definition: protocol.h:82
#define PqReplMsg_StandbyStatusUpdate
Definition: protocol.h:84
static void ProcessStandbyHSFeedbackMessage(void)
Definition: walsender.c:2599
static void ProcessStandbyPSRequestMessage(void)
Definition: walsender.c:2719
static void ProcessStandbyReplyMessage(void)
Definition: walsender.c:2414

References COMMERROR, ereport, errcode(), errmsg(), pq_getmsgbyte(), PqReplMsg_HotStandbyFeedback, PqReplMsg_PrimaryStatusRequest, PqReplMsg_StandbyStatusUpdate, proc_exit(), ProcessStandbyHSFeedbackMessage(), ProcessStandbyPSRequestMessage(), ProcessStandbyReplyMessage(), and reply_message.

Referenced by ProcessRepliesIfAny().

◆ ProcessStandbyPSRequestMessage()

static void ProcessStandbyPSRequestMessage ( void  )
static

Definition at line 2719 of file walsender.c.

2720{
2722 TransactionId oldestXidInCommit;
2723 TransactionId oldestGXidInCommit;
2724 FullTransactionId nextFullXid;
2725 FullTransactionId fullOldestXidInCommit;
2726 WalSnd *walsnd = MyWalSnd;
2727 TimestampTz replyTime;
2728
2729 /*
2730 * This shouldn't happen because we don't support getting primary status
2731 * message from standby.
2732 */
2733 if (RecoveryInProgress())
2734 elog(ERROR, "the primary status is unavailable during recovery");
2735
2736 replyTime = pq_getmsgint64(&reply_message);
2737
2738 /*
2739 * Update shared state for this WalSender process based on reply data from
2740 * standby.
2741 */
2742 SpinLockAcquire(&walsnd->mutex);
2743 walsnd->replyTime = replyTime;
2744 SpinLockRelease(&walsnd->mutex);
2745
2746 /*
2747 * Consider transactions in the current database, as only these are the
2748 * ones replicated.
2749 */
2750 oldestXidInCommit = GetOldestActiveTransactionId(true, false);
2751 oldestGXidInCommit = TwoPhaseGetOldestXidInCommit();
2752
2753 /*
2754 * Update the oldest xid for standby transmission if an older prepared
2755 * transaction exists and is currently in commit phase.
2756 */
2757 if (TransactionIdIsValid(oldestGXidInCommit) &&
2758 TransactionIdPrecedes(oldestGXidInCommit, oldestXidInCommit))
2759 oldestXidInCommit = oldestGXidInCommit;
2760
2761 nextFullXid = ReadNextFullTransactionId();
2762 fullOldestXidInCommit = FullTransactionIdFromAllowableAt(nextFullXid,
2763 oldestXidInCommit);
2764 lsn = GetXLogWriteRecPtr();
2765
2766 elog(DEBUG2, "sending primary status");
2767
2768 /* construct the message... */
2772 pq_sendint64(&output_message, (int64) U64FromFullTransactionId(fullOldestXidInCommit));
2775
2776 /* ... and send it wrapped in CopyData */
2778}
int64_t int64
Definition: c.h:535
static void pq_sendbyte(StringInfo buf, uint8 byt)
Definition: pqformat.h:160
static void pq_sendint64(StringInfo buf, uint64 i)
Definition: pqformat.h:152
TransactionId GetOldestActiveTransactionId(bool inCommitOnly, bool allDbs)
Definition: procarray.c:2833
#define PqReplMsg_PrimaryStatusUpdate
Definition: protocol.h:76
static FullTransactionId FullTransactionIdFromAllowableAt(FullTransactionId nextFullXid, TransactionId xid)
Definition: transam.h:381
#define U64FromFullTransactionId(x)
Definition: transam.h:49
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId TwoPhaseGetOldestXidInCommit(void)
Definition: twophase.c:2829
FullTransactionId ReadNextFullTransactionId(void)
Definition: varsup.c:288
XLogRecPtr GetXLogWriteRecPtr(void)
Definition: xlog.c:9495

References StringInfoData::data, DEBUG2, elog, ERROR, FullTransactionIdFromAllowableAt(), GetCurrentTimestamp(), GetOldestActiveTransactionId(), GetXLogWriteRecPtr(), InvalidXLogRecPtr, StringInfoData::len, WalSnd::mutex, MyWalSnd, output_message, pq_getmsgint64(), pq_putmessage_noblock, pq_sendbyte(), pq_sendint64(), PqMsg_CopyData, PqReplMsg_PrimaryStatusUpdate, ReadNextFullTransactionId(), RecoveryInProgress(), reply_message, WalSnd::replyTime, resetStringInfo(), SpinLockAcquire, SpinLockRelease, TransactionIdIsValid, TransactionIdPrecedes(), TwoPhaseGetOldestXidInCommit(), and U64FromFullTransactionId.

Referenced by ProcessStandbyMessage().

◆ ProcessStandbyReplyMessage()

static void ProcessStandbyReplyMessage ( void  )
static

Definition at line 2414 of file walsender.c.

2415{
2416 XLogRecPtr writePtr,
2417 flushPtr,
2418 applyPtr;
2419 bool replyRequested;
2420 TimeOffset writeLag,
2421 flushLag,
2422 applyLag;
2423 bool clearLagTimes;
2425 TimestampTz replyTime;
2426
2427 static bool fullyAppliedLastTime = false;
2428
2429 /* the caller already consumed the msgtype byte */
2430 writePtr = pq_getmsgint64(&reply_message);
2431 flushPtr = pq_getmsgint64(&reply_message);
2432 applyPtr = pq_getmsgint64(&reply_message);
2433 replyTime = pq_getmsgint64(&reply_message);
2434 replyRequested = pq_getmsgbyte(&reply_message);
2435
2437 {
2438 char *replyTimeStr;
2439
2440 /* Copy because timestamptz_to_str returns a static buffer */
2441 replyTimeStr = pstrdup(timestamptz_to_str(replyTime));
2442
2443 elog(DEBUG2, "write %X/%08X flush %X/%08X apply %X/%08X%s reply_time %s",
2444 LSN_FORMAT_ARGS(writePtr),
2445 LSN_FORMAT_ARGS(flushPtr),
2446 LSN_FORMAT_ARGS(applyPtr),
2447 replyRequested ? " (reply requested)" : "",
2448 replyTimeStr);
2449
2450 pfree(replyTimeStr);
2451 }
2452
2453 /* See if we can compute the round-trip lag for these positions. */
2455 writeLag = LagTrackerRead(SYNC_REP_WAIT_WRITE, writePtr, now);
2456 flushLag = LagTrackerRead(SYNC_REP_WAIT_FLUSH, flushPtr, now);
2457 applyLag = LagTrackerRead(SYNC_REP_WAIT_APPLY, applyPtr, now);
2458
2459 /*
2460 * If the standby reports that it has fully replayed the WAL in two
2461 * consecutive reply messages, then the second such message must result
2462 * from wal_receiver_status_interval expiring on the standby. This is a
2463 * convenient time to forget the lag times measured when it last
2464 * wrote/flushed/applied a WAL record, to avoid displaying stale lag data
2465 * until more WAL traffic arrives.
2466 */
2467 clearLagTimes = false;
2468 if (applyPtr == sentPtr)
2469 {
2470 if (fullyAppliedLastTime)
2471 clearLagTimes = true;
2472 fullyAppliedLastTime = true;
2473 }
2474 else
2475 fullyAppliedLastTime = false;
2476
2477 /* Send a reply if the standby requested one. */
2478 if (replyRequested)
2480
2481 /*
2482 * Update shared state for this WalSender process based on reply data from
2483 * standby.
2484 */
2485 {
2486 WalSnd *walsnd = MyWalSnd;
2487
2488 SpinLockAcquire(&walsnd->mutex);
2489 walsnd->write = writePtr;
2490 walsnd->flush = flushPtr;
2491 walsnd->apply = applyPtr;
2492 if (writeLag != -1 || clearLagTimes)
2493 walsnd->writeLag = writeLag;
2494 if (flushLag != -1 || clearLagTimes)
2495 walsnd->flushLag = flushLag;
2496 if (applyLag != -1 || clearLagTimes)
2497 walsnd->applyLag = applyLag;
2498 walsnd->replyTime = replyTime;
2499 SpinLockRelease(&walsnd->mutex);
2500 }
2501
2504
2505 /*
2506 * Advance our local xmin horizon when the client confirmed a flush.
2507 */
2508 if (MyReplicationSlot && flushPtr != InvalidXLogRecPtr)
2509 {
2512 else
2514 }
2515}
void LogicalConfirmReceivedLocation(XLogRecPtr lsn)
Definition: logical.c:1820
#define SlotIsLogical(slot)
Definition: slot.h:255
void SyncRepReleaseWaiters(void)
Definition: syncrep.c:474
#define SYNC_REP_WAIT_WRITE
Definition: syncrep.h:23
#define SYNC_REP_WAIT_FLUSH
Definition: syncrep.h:24
#define SYNC_REP_WAIT_APPLY
Definition: syncrep.h:25
static XLogRecPtr sentPtr
Definition: walsender.c:173
static void PhysicalConfirmReceivedLocation(XLogRecPtr lsn)
Definition: walsender.c:2381
static void WalSndKeepalive(bool requestReply, XLogRecPtr writePtr)
Definition: walsender.c:4147
static TimeOffset LagTrackerRead(int head, XLogRecPtr lsn, TimestampTz now)
Definition: walsender.c:4273

References am_cascading_walsender, WalSnd::apply, WalSnd::applyLag, DEBUG2, elog, WalSnd::flush, WalSnd::flushLag, GetCurrentTimestamp(), InvalidXLogRecPtr, LagTrackerRead(), LogicalConfirmReceivedLocation(), LSN_FORMAT_ARGS, message_level_is_interesting(), WalSnd::mutex, MyReplicationSlot, MyWalSnd, now(), pfree(), PhysicalConfirmReceivedLocation(), pq_getmsgbyte(), pq_getmsgint64(), pstrdup(), reply_message, WalSnd::replyTime, sentPtr, SlotIsLogical, SpinLockAcquire, SpinLockRelease, SYNC_REP_WAIT_APPLY, SYNC_REP_WAIT_FLUSH, SYNC_REP_WAIT_WRITE, SyncRepReleaseWaiters(), timestamptz_to_str(), WalSndKeepalive(), WalSnd::write, and WalSnd::writeLag.

Referenced by ProcessStandbyMessage().

◆ ReadReplicationSlot()

static void ReadReplicationSlot ( ReadReplicationSlotCmd cmd)
static

Definition at line 468 of file walsender.c.

469{
470#define READ_REPLICATION_SLOT_COLS 3
471 ReplicationSlot *slot;
473 TupOutputState *tstate;
474 TupleDesc tupdesc;
476 bool nulls[READ_REPLICATION_SLOT_COLS];
477
479 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "slot_type",
480 TEXTOID, -1, 0);
481 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "restart_lsn",
482 TEXTOID, -1, 0);
483 /* TimeLineID is unsigned, so int4 is not wide enough. */
484 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 3, "restart_tli",
485 INT8OID, -1, 0);
486
487 memset(nulls, true, READ_REPLICATION_SLOT_COLS * sizeof(bool));
488
489 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
490 slot = SearchNamedReplicationSlot(cmd->slotname, false);
491 if (slot == NULL || !slot->in_use)
492 {
493 LWLockRelease(ReplicationSlotControlLock);
494 }
495 else
496 {
497 ReplicationSlot slot_contents;
498 int i = 0;
499
500 /* Copy slot contents while holding spinlock */
501 SpinLockAcquire(&slot->mutex);
502 slot_contents = *slot;
503 SpinLockRelease(&slot->mutex);
504 LWLockRelease(ReplicationSlotControlLock);
505
506 if (OidIsValid(slot_contents.data.database))
508 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
509 errmsg("cannot use %s with a logical replication slot",
510 "READ_REPLICATION_SLOT"));
511
512 /* slot type */
513 values[i] = CStringGetTextDatum("physical");
514 nulls[i] = false;
515 i++;
516
517 /* start LSN */
518 if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
519 {
520 char xloc[64];
521
522 snprintf(xloc, sizeof(xloc), "%X/%08X",
523 LSN_FORMAT_ARGS(slot_contents.data.restart_lsn));
525 nulls[i] = false;
526 }
527 i++;
528
529 /* timeline this WAL was produced on */
530 if (!XLogRecPtrIsInvalid(slot_contents.data.restart_lsn))
531 {
532 TimeLineID slots_position_timeline;
533 TimeLineID current_timeline;
534 List *timeline_history = NIL;
535
536 /*
537 * While in recovery, use as timeline the currently-replaying one
538 * to get the LSN position's history.
539 */
540 if (RecoveryInProgress())
541 (void) GetXLogReplayRecPtr(&current_timeline);
542 else
543 current_timeline = GetWALInsertionTimeLine();
544
545 timeline_history = readTimeLineHistory(current_timeline);
546 slots_position_timeline = tliOfPointInHistory(slot_contents.data.restart_lsn,
547 timeline_history);
548 values[i] = Int64GetDatum((int64) slots_position_timeline);
549 nulls[i] = false;
550 }
551 i++;
552
554 }
555
557 tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
558 do_tup_output(tstate, values, nulls);
559 end_tup_output(tstate);
560}
List * readTimeLineHistory(TimeLineID targetTLI)
Definition: timeline.c:76
TimeLineID tliOfPointInHistory(XLogRecPtr ptr, List *history)
Definition: timeline.c:544
#define OidIsValid(objectId)
Definition: c.h:774
@ LW_SHARED
Definition: lwlock.h:113
ReplicationSlot * SearchNamedReplicationSlot(const char *name, bool need_lock)
Definition: slot.c:513
Definition: pg_list.h:54
bool in_use
Definition: slot.h:168
#define READ_REPLICATION_SLOT_COLS

References Assert(), begin_tup_output_tupdesc(), CreateDestReceiver(), CreateTemplateTupleDesc(), CStringGetTextDatum, ReplicationSlot::data, ReplicationSlotPersistentData::database, generate_unaccent_rules::dest, DestRemoteSimple, do_tup_output(), end_tup_output(), ereport, errcode(), errmsg(), ERROR, GetWALInsertionTimeLine(), GetXLogReplayRecPtr(), i, ReplicationSlot::in_use, Int64GetDatum(), LSN_FORMAT_ARGS, LW_SHARED, LWLockAcquire(), LWLockRelease(), ReplicationSlot::mutex, NIL, OidIsValid, READ_REPLICATION_SLOT_COLS, readTimeLineHistory(), RecoveryInProgress(), ReplicationSlotPersistentData::restart_lsn, SearchNamedReplicationSlot(), ReadReplicationSlotCmd::slotname, snprintf, SpinLockAcquire, SpinLockRelease, tliOfPointInHistory(), TTSOpsVirtual, TupleDescInitBuiltinEntry(), values, and XLogRecPtrIsInvalid.

Referenced by exec_replication_command().

◆ SendTimeLineHistory()

static void SendTimeLineHistory ( TimeLineHistoryCmd cmd)
static

Definition at line 567 of file walsender.c.

568{
570 TupleDesc tupdesc;
572 char histfname[MAXFNAMELEN];
573 char path[MAXPGPATH];
574 int fd;
575 off_t histfilelen;
576 off_t bytesleft;
577 Size len;
578
580
581 /*
582 * Reply with a result set with one row, and two columns. The first col is
583 * the name of the history file, 2nd is the contents.
584 */
585 tupdesc = CreateTemplateTupleDesc(2);
586 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "filename", TEXTOID, -1, 0);
587 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "content", TEXTOID, -1, 0);
588
589 TLHistoryFileName(histfname, cmd->timeline);
590 TLHistoryFilePath(path, cmd->timeline);
591
592 /* Send a RowDescription message */
593 dest->rStartup(dest, CMD_SELECT, tupdesc);
594
595 /* Send a DataRow message */
597 pq_sendint16(&buf, 2); /* # of columns */
598 len = strlen(histfname);
599 pq_sendint32(&buf, len); /* col1 len */
600 pq_sendbytes(&buf, histfname, len);
601
602 fd = OpenTransientFile(path, O_RDONLY | PG_BINARY);
603 if (fd < 0)
606 errmsg("could not open file \"%s\": %m", path)));
607
608 /* Determine file length and send it to client */
609 histfilelen = lseek(fd, 0, SEEK_END);
610 if (histfilelen < 0)
613 errmsg("could not seek to end of file \"%s\": %m", path)));
614 if (lseek(fd, 0, SEEK_SET) != 0)
617 errmsg("could not seek to beginning of file \"%s\": %m", path)));
618
619 pq_sendint32(&buf, histfilelen); /* col2 len */
620
621 bytesleft = histfilelen;
622 while (bytesleft > 0)
623 {
624 PGAlignedBlock rbuf;
625 int nread;
626
627 pgstat_report_wait_start(WAIT_EVENT_WALSENDER_TIMELINE_HISTORY_READ);
628 nread = read(fd, rbuf.data, sizeof(rbuf));
630 if (nread < 0)
633 errmsg("could not read file \"%s\": %m",
634 path)));
635 else if (nread == 0)
638 errmsg("could not read file \"%s\": read %d of %zu",
639 path, nread, (Size) bytesleft)));
640
641 pq_sendbytes(&buf, rbuf.data, nread);
642 bytesleft -= nread;
643 }
644
645 if (CloseTransientFile(fd) != 0)
648 errmsg("could not close file \"%s\": %m", path)));
649
651}
#define PG_BINARY
Definition: c.h:1272
size_t Size
Definition: c.h:610
int errcode_for_file_access(void)
Definition: elog.c:877
int CloseTransientFile(int fd)
Definition: fd.c:2868
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2691
#define read(a, b, c)
Definition: win32.h:13
@ CMD_SELECT
Definition: nodes.h:275
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:42
#define MAXPGPATH
const void size_t len
void pq_sendbytes(StringInfo buf, const void *data, int datalen)
Definition: pqformat.c:126
void pq_endmessage(StringInfo buf)
Definition: pqformat.c:296
void pq_beginmessage(StringInfo buf, char msgtype)
Definition: pqformat.c:88
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
static void pq_sendint16(StringInfo buf, uint16 i)
Definition: pqformat.h:136
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PqMsg_DataRow
Definition: protocol.h:43
TimeLineID timeline
Definition: replnodes.h:120
char data[BLCKSZ]
Definition: c.h:1118
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:69
static void pgstat_report_wait_end(void)
Definition: wait_event.h:85
static void TLHistoryFilePath(char *path, TimeLineID tli)
static void TLHistoryFileName(char *fname, TimeLineID tli)

References buf, CloseTransientFile(), CMD_SELECT, CreateDestReceiver(), CreateTemplateTupleDesc(), PGAlignedBlock::data, generate_unaccent_rules::dest, DestRemoteSimple, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errcode_for_file_access(), errmsg(), ERROR, fd(), len, MAXFNAMELEN, MAXPGPATH, OpenTransientFile(), PG_BINARY, pgstat_report_wait_end(), pgstat_report_wait_start(), pq_beginmessage(), pq_endmessage(), pq_sendbytes(), pq_sendint16(), pq_sendint32(), PqMsg_DataRow, read, TimeLineHistoryCmd::timeline, TLHistoryFileName(), TLHistoryFilePath(), and TupleDescInitBuiltinEntry().

Referenced by exec_replication_command().

◆ StartLogicalReplication()

static void StartLogicalReplication ( StartReplicationCmd cmd)
static

Definition at line 1437 of file walsender.c.

1438{
1440 QueryCompletion qc;
1441
1442 /* make sure that our requirements are still fulfilled */
1444
1446
1447 ReplicationSlotAcquire(cmd->slotname, true, true);
1448
1449 /*
1450 * Force a disconnect, so that the decoding code doesn't need to care
1451 * about an eventual switch from running in recovery, to running in a
1452 * normal environment. Client code is expected to handle reconnects.
1453 */
1455 {
1456 ereport(LOG,
1457 (errmsg("terminating walsender process after promotion")));
1458 got_STOPPING = true;
1459 }
1460
1461 /*
1462 * Create our decoding context, making it start at the previously ack'ed
1463 * position.
1464 *
1465 * Do this before sending a CopyBothResponse message, so that any errors
1466 * are reported early.
1467 */
1469 CreateDecodingContext(cmd->startpoint, cmd->options, false,
1471 .segment_open = WalSndSegmentOpen,
1472 .segment_close = wal_segment_close),
1476
1478
1479 /* Send a CopyBothResponse message, and start streaming */
1481 pq_sendbyte(&buf, 0);
1482 pq_sendint16(&buf, 0);
1484 pq_flush();
1485
1486 /* Start reading WAL from the oldest required WAL. */
1489
1490 /*
1491 * Report the location after which we'll send out further commits as the
1492 * current sentPtr.
1493 */
1495
1496 /* Also update the sent position status in shared memory */
1500
1501 replication_active = true;
1502
1504
1505 /* Main loop of walsender */
1507
1510
1511 replication_active = false;
1512 if (got_STOPPING)
1513 proc_exit(0);
1515
1516 /* Get out of COPY mode (CommandComplete). */
1517 SetQueryCompletion(&qc, CMDTAG_COPY, 0);
1518 EndCommand(&qc, DestRemote, false);
1519}
static void SetQueryCompletion(QueryCompletion *qc, CommandTag commandTag, uint64 nprocessed)
Definition: cmdtag.h:37
void EndCommand(const QueryCompletion *qc, CommandDest dest, bool force_undecorated_output)
Definition: dest.c:169
@ DestRemote
Definition: dest.h:89
#define pq_flush()
Definition: libpq.h:46
LogicalDecodingContext * CreateDecodingContext(XLogRecPtr start_lsn, List *output_plugin_options, bool fast_forward, XLogReaderRoutine *xl_routine, LogicalOutputPluginWriterPrepareWrite prepare_write, LogicalOutputPluginWriterWrite do_write, LogicalOutputPluginWriterUpdateProgress update_progress)
Definition: logical.c:498
#define PqMsg_CopyBothResponse
Definition: protocol.h:54
void ReplicationSlotAcquire(const char *name, bool nowait, bool error_if_invalid)
Definition: slot.c:593
XLogReaderState * reader
Definition: logical.h:42
XLogRecPtr startpoint
Definition: replnodes.h:97
static void WalSndLoop(WalSndSendDataCallback send_data)
Definition: walsender.c:2859
static LogicalDecodingContext * logical_decoding_ctx
Definition: walsender.c:216
static void XLogSendLogical(void)
Definition: walsender.c:3481
@ WALSNDSTATE_CATCHUP
void XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr)
Definition: xlogreader.c:232

References am_cascading_walsender, Assert(), buf, CheckLogicalDecodingRequirements(), ReplicationSlotPersistentData::confirmed_flush, CreateDecodingContext(), ReplicationSlot::data, DestRemote, EndCommand(), ereport, errmsg(), FreeDecodingContext(), got_STOPPING, LOG, logical_decoding_ctx, logical_read_xlog_page(), WalSnd::mutex, MyReplicationSlot, MyWalSnd, StartReplicationCmd::options, pq_beginmessage(), pq_endmessage(), pq_flush, pq_sendbyte(), pq_sendint16(), PqMsg_CopyBothResponse, proc_exit(), LogicalDecodingContext::reader, RecoveryInProgress(), replication_active, ReplicationSlotAcquire(), ReplicationSlotRelease(), ReplicationSlotPersistentData::restart_lsn, sentPtr, WalSnd::sentPtr, SetQueryCompletion(), StartReplicationCmd::slotname, SpinLockAcquire, SpinLockRelease, StartReplicationCmd::startpoint, SyncRepInitConfig(), wal_segment_close(), WalSndLoop(), WalSndPrepareWrite(), WalSndSegmentOpen(), WalSndSetState(), WALSNDSTATE_CATCHUP, WALSNDSTATE_STARTUP, WalSndUpdateProgress(), WalSndWriteData(), XL_ROUTINE, XLogBeginRead(), xlogreader, and XLogSendLogical().

Referenced by exec_replication_command().

◆ StartReplication()

static void StartReplication ( StartReplicationCmd cmd)
static

Definition at line 799 of file walsender.c.

800{
802 XLogRecPtr FlushPtr;
803 TimeLineID FlushTLI;
804
805 /* create xlogreader for physical replication */
806 xlogreader =
808 XL_ROUTINE(.segment_open = WalSndSegmentOpen,
809 .segment_close = wal_segment_close),
810 NULL);
811
812 if (!xlogreader)
814 (errcode(ERRCODE_OUT_OF_MEMORY),
815 errmsg("out of memory"),
816 errdetail("Failed while allocating a WAL reading processor.")));
817
818 /*
819 * We assume here that we're logging enough information in the WAL for
820 * log-shipping, since this is checked in PostmasterMain().
821 *
822 * NOTE: wal_level can only change at shutdown, so in most cases it is
823 * difficult for there to be WAL data that we can still see that was
824 * written at wal_level='minimal'.
825 */
826
827 if (cmd->slotname)
828 {
829 ReplicationSlotAcquire(cmd->slotname, true, true);
832 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
833 errmsg("cannot use a logical replication slot for physical replication")));
834
835 /*
836 * We don't need to verify the slot's restart_lsn here; instead we
837 * rely on the caller requesting the starting point to use. If the
838 * WAL segment doesn't exist, we'll fail later.
839 */
840 }
841
842 /*
843 * Select the timeline. If it was given explicitly by the client, use
844 * that. Otherwise use the timeline of the last replayed record.
845 */
848 FlushPtr = GetStandbyFlushRecPtr(&FlushTLI);
849 else
850 FlushPtr = GetFlushRecPtr(&FlushTLI);
851
852 if (cmd->timeline != 0)
853 {
854 XLogRecPtr switchpoint;
855
856 sendTimeLine = cmd->timeline;
857 if (sendTimeLine == FlushTLI)
858 {
861 }
862 else
863 {
864 List *timeLineHistory;
865
867
868 /*
869 * Check that the timeline the client requested exists, and the
870 * requested start location is on that timeline.
871 */
872 timeLineHistory = readTimeLineHistory(FlushTLI);
873 switchpoint = tliSwitchPoint(cmd->timeline, timeLineHistory,
875 list_free_deep(timeLineHistory);
876
877 /*
878 * Found the requested timeline in the history. Check that
879 * requested startpoint is on that timeline in our history.
880 *
881 * This is quite loose on purpose. We only check that we didn't
882 * fork off the requested timeline before the switchpoint. We
883 * don't check that we switched *to* it before the requested
884 * starting point. This is because the client can legitimately
885 * request to start replication from the beginning of the WAL
886 * segment that contains switchpoint, but on the new timeline, so
887 * that it doesn't end up with a partial segment. If you ask for
888 * too old a starting point, you'll get an error later when we
889 * fail to find the requested WAL segment in pg_wal.
890 *
891 * XXX: we could be more strict here and only allow a startpoint
892 * that's older than the switchpoint, if it's still in the same
893 * WAL segment.
894 */
895 if (!XLogRecPtrIsInvalid(switchpoint) &&
896 switchpoint < cmd->startpoint)
897 {
899 errmsg("requested starting point %X/%08X on timeline %u is not in this server's history",
901 cmd->timeline),
902 errdetail("This server's history forked from timeline %u at %X/%08X.",
903 cmd->timeline,
904 LSN_FORMAT_ARGS(switchpoint)));
905 }
906 sendTimeLineValidUpto = switchpoint;
907 }
908 }
909 else
910 {
911 sendTimeLine = FlushTLI;
914 }
915
917
918 /* If there is nothing to stream, don't even enter COPY mode */
920 {
921 /*
922 * When we first start replication the standby will be behind the
923 * primary. For some applications, for example synchronous
924 * replication, it is important to have a clear state for this initial
925 * catchup mode, so we can trigger actions when we change streaming
926 * state later. We may stay in this state for a long time, which is
927 * exactly why we want to be able to monitor whether or not we are
928 * still here.
929 */
931
932 /* Send a CopyBothResponse message, and start streaming */
934 pq_sendbyte(&buf, 0);
935 pq_sendint16(&buf, 0);
937 pq_flush();
938
939 /*
940 * Don't allow a request to stream from a future point in WAL that
941 * hasn't been flushed to disk in this server yet.
942 */
943 if (FlushPtr < cmd->startpoint)
944 {
946 errmsg("requested starting point %X/%08X is ahead of the WAL flush position of this server %X/%08X",
948 LSN_FORMAT_ARGS(FlushPtr)));
949 }
950
951 /* Start streaming from the requested point */
952 sentPtr = cmd->startpoint;
953
954 /* Initialize shared memory status, too */
958
960
961 /* Main loop of walsender */
962 replication_active = true;
963
965
966 replication_active = false;
967 if (got_STOPPING)
968 proc_exit(0);
970
972 }
973
974 if (cmd->slotname)
976
977 /*
978 * Copy is finished now. Send a single-row result set indicating the next
979 * timeline.
980 */
982 {
983 char startpos_str[8 + 1 + 8 + 1];
985 TupOutputState *tstate;
986 TupleDesc tupdesc;
987 Datum values[2];
988 bool nulls[2] = {0};
989
990 snprintf(startpos_str, sizeof(startpos_str), "%X/%08X",
992
994
995 /*
996 * Need a tuple descriptor representing two columns. int8 may seem
997 * like a surprising data type for this, but in theory int4 would not
998 * be wide enough for this, as TimeLineID is unsigned.
999 */
1000 tupdesc = CreateTemplateTupleDesc(2);
1001 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 1, "next_tli",
1002 INT8OID, -1, 0);
1003 TupleDescInitBuiltinEntry(tupdesc, (AttrNumber) 2, "next_tli_startpos",
1004 TEXTOID, -1, 0);
1005
1006 /* prepare for projection of tuple */
1007 tstate = begin_tup_output_tupdesc(dest, tupdesc, &TTSOpsVirtual);
1008
1010 values[1] = CStringGetTextDatum(startpos_str);
1011
1012 /* send it to dest */
1013 do_tup_output(tstate, values, nulls);
1014
1015 end_tup_output(tstate);
1016 }
1017
1018 /* Send CommandComplete message */
1019 EndReplicationCommand("START_STREAMING");
1020}
XLogRecPtr tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
Definition: timeline.c:572
int errdetail(const char *fmt,...)
Definition: elog.c:1207
void list_free_deep(List *list)
Definition: list.c:1560
TimeLineID timeline
Definition: replnodes.h:96
static void XLogSendPhysical(void)
Definition: walsender.c:3171
int wal_segment_size
Definition: xlog.c:144
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition: xlogreader.c:107

References am_cascading_walsender, Assert(), begin_tup_output_tupdesc(), buf, CreateDestReceiver(), CreateTemplateTupleDesc(), CStringGetTextDatum, generate_unaccent_rules::dest, DestRemoteSimple, do_tup_output(), end_tup_output(), EndReplicationCommand(), ereport, errcode(), errdetail(), errmsg(), ERROR, GetFlushRecPtr(), GetStandbyFlushRecPtr(), got_STOPPING, Int64GetDatum(), InvalidXLogRecPtr, list_free_deep(), LSN_FORMAT_ARGS, WalSnd::mutex, MyReplicationSlot, MyWalSnd, pq_beginmessage(), pq_endmessage(), pq_flush, pq_sendbyte(), pq_sendint16(), PqMsg_CopyBothResponse, proc_exit(), readTimeLineHistory(), RecoveryInProgress(), replication_active, ReplicationSlotAcquire(), ReplicationSlotRelease(), sendTimeLine, sendTimeLineIsHistoric, sendTimeLineNextTLI, sendTimeLineValidUpto, sentPtr, WalSnd::sentPtr, SlotIsLogical, StartReplicationCmd::slotname, snprintf, SpinLockAcquire, SpinLockRelease, StartReplicationCmd::startpoint, streamingDoneReceiving, streamingDoneSending, SyncRepInitConfig(), StartReplicationCmd::timeline, tliSwitchPoint(), TTSOpsVirtual, TupleDescInitBuiltinEntry(), values, wal_segment_close(), wal_segment_size, WalSndLoop(), WalSndSegmentOpen(), WalSndSetState(), WALSNDSTATE_CATCHUP, WALSNDSTATE_STARTUP, XL_ROUTINE, xlogreader, XLogReaderAllocate(), XLogRecPtrIsInvalid, and XLogSendPhysical().

Referenced by exec_replication_command().

◆ TransactionIdInRecentPast()

static bool TransactionIdInRecentPast ( TransactionId  xid,
uint32  epoch 
)
static

Definition at line 2568 of file walsender.c.

2569{
2570 FullTransactionId nextFullXid;
2571 TransactionId nextXid;
2572 uint32 nextEpoch;
2573
2574 nextFullXid = ReadNextFullTransactionId();
2575 nextXid = XidFromFullTransactionId(nextFullXid);
2576 nextEpoch = EpochFromFullTransactionId(nextFullXid);
2577
2578 if (xid <= nextXid)
2579 {
2580 if (epoch != nextEpoch)
2581 return false;
2582 }
2583 else
2584 {
2585 if (epoch + 1 != nextEpoch)
2586 return false;
2587 }
2588
2589 if (!TransactionIdPrecedesOrEquals(xid, nextXid))
2590 return false; /* epoch OK, but it's wrapped around */
2591
2592 return true;
2593}
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:299
#define EpochFromFullTransactionId(x)
Definition: transam.h:47
#define XidFromFullTransactionId(x)
Definition: transam.h:48
static const unsigned __int64 epoch

References epoch, EpochFromFullTransactionId, ReadNextFullTransactionId(), TransactionIdPrecedesOrEquals(), and XidFromFullTransactionId.

Referenced by ProcessStandbyHSFeedbackMessage().

◆ UploadManifest()

static void UploadManifest ( void  )
static

Definition at line 657 of file walsender.c.

658{
659 MemoryContext mcxt;
661 off_t offset = 0;
663
664 /*
665 * parsing the manifest will use the cryptohash stuff, which requires a
666 * resource owner
667 */
670 CurrentResourceOwner == NULL);
672
673 /* Prepare to read manifest data into a temporary context. */
675 "incremental backup information",
678
679 /* Send a CopyInResponse message */
681 pq_sendbyte(&buf, 0);
682 pq_sendint16(&buf, 0);
684 pq_flush();
685
686 /* Receive packets from client until done. */
687 while (HandleUploadManifestPacket(&buf, &offset, ib))
688 ;
689
690 /* Finish up manifest processing. */
692
693 /*
694 * Discard any old manifest information and arrange to preserve the new
695 * information we just got.
696 *
697 * We assume that MemoryContextDelete and MemoryContextSetParent won't
698 * fail, and thus we shouldn't end up bailing out of here in such a way as
699 * to leave dangling pointers.
700 */
701 if (uploaded_manifest_mcxt != NULL)
706
707 /* clean up the resource owner we created */
709}
IncrementalBackupInfo * CreateIncrementalBackupInfo(MemoryContext mcxt)
void FinalizeIncrementalManifest(IncrementalBackupInfo *ib)
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:683
MemoryContext CacheMemoryContext
Definition: mcxt.c:169
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:469
void pq_endmessage_reuse(StringInfo buf)
Definition: pqformat.c:314
#define PqMsg_CopyInResponse
Definition: protocol.h:45
void ReleaseAuxProcessResources(bool isCommit)
Definition: resowner.c:1016
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173
ResourceOwner AuxProcessResourceOwner
Definition: resowner.c:176
static bool HandleUploadManifestPacket(StringInfo buf, off_t *offset, IncrementalBackupInfo *ib)
Definition: walsender.c:723
static MemoryContext uploaded_manifest_mcxt
Definition: walsender.c:156

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), AuxProcessResourceOwner, buf, CacheMemoryContext, CreateIncrementalBackupInfo(), CurrentMemoryContext, CurrentResourceOwner, FinalizeIncrementalManifest(), HandleUploadManifestPacket(), MemoryContextDelete(), MemoryContextSetParent(), pq_beginmessage(), pq_endmessage_reuse(), pq_flush, pq_sendbyte(), pq_sendint16(), PqMsg_CopyInResponse, ReleaseAuxProcessResources(), uploaded_manifest, and uploaded_manifest_mcxt.

Referenced by exec_replication_command().

◆ WalSndCheckTimeOut()

static void WalSndCheckTimeOut ( void  )
static

Definition at line 2832 of file walsender.c.

2833{
2834 TimestampTz timeout;
2835
2836 /* don't bail out if we're doing something that doesn't require timeouts */
2837 if (last_reply_timestamp <= 0)
2838 return;
2839
2842
2843 if (wal_sender_timeout > 0 && last_processing >= timeout)
2844 {
2845 /*
2846 * Since typically expiration of replication timeout means
2847 * communication problem, we don't send the error message to the
2848 * standby.
2849 */
2851 (errmsg("terminating walsender process due to replication timeout")));
2852
2854 }
2855}
#define TimestampTzPlusMilliseconds(tz, ms)
Definition: timestamp.h:85
int wal_sender_timeout
Definition: walsender.c:131

References COMMERROR, ereport, errmsg(), last_processing, last_reply_timestamp, TimestampTzPlusMilliseconds, wal_sender_timeout, and WalSndShutdown().

Referenced by ProcessPendingWrites(), WalSndLoop(), and WalSndWaitForWal().

◆ WalSndComputeSleeptime()

static long WalSndComputeSleeptime ( TimestampTz  now)
static

Definition at line 2788 of file walsender.c.

2789{
2790 long sleeptime = 10000; /* 10 s */
2791
2793 {
2794 TimestampTz wakeup_time;
2795
2796 /*
2797 * At the latest stop sleeping once wal_sender_timeout has been
2798 * reached.
2799 */
2802
2803 /*
2804 * If no ping has been sent yet, wakeup when it's time to do so.
2805 * WalSndKeepaliveIfNecessary() wants to send a keepalive once half of
2806 * the timeout passed without a response.
2807 */
2810 wal_sender_timeout / 2);
2811
2812 /* Compute relative time until wakeup. */
2813 sleeptime = TimestampDifferenceMilliseconds(now, wakeup_time);
2814 }
2815
2816 return sleeptime;
2817}
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition: timestamp.c:1757

References last_reply_timestamp, now(), TimestampDifferenceMilliseconds(), TimestampTzPlusMilliseconds, waiting_for_ping_response, and wal_sender_timeout.

Referenced by ProcessPendingWrites(), WalSndLoop(), and WalSndWaitForWal().

◆ WalSndDone()

static void WalSndDone ( WalSndSendDataCallback  send_data)
static

Definition at line 3574 of file walsender.c.

3575{
3576 XLogRecPtr replicatedPtr;
3577
3578 /* ... let's just be real sure we're caught up ... */
3579 send_data();
3580
3581 /*
3582 * To figure out whether all WAL has successfully been replicated, check
3583 * flush location if valid, write otherwise. Tools like pg_receivewal will
3584 * usually (unless in synchronous mode) return an invalid flush location.
3585 */
3586 replicatedPtr = XLogRecPtrIsInvalid(MyWalSnd->flush) ?
3588
3589 if (WalSndCaughtUp && sentPtr == replicatedPtr &&
3591 {
3592 QueryCompletion qc;
3593
3594 /* Inform the standby that XLOG streaming is done */
3595 SetQueryCompletion(&qc, CMDTAG_COPY, 0);
3596 EndCommand(&qc, DestRemote, false);
3597 pq_flush();
3598
3599 proc_exit(0);
3600 }
3603}
static bool WalSndCaughtUp
Definition: walsender.c:202

References DestRemote, EndCommand(), WalSnd::flush, InvalidXLogRecPtr, MyWalSnd, pq_flush, pq_is_send_pending, proc_exit(), sentPtr, SetQueryCompletion(), waiting_for_ping_response, WalSndCaughtUp, WalSndKeepalive(), WalSnd::write, and XLogRecPtrIsInvalid.

Referenced by WalSndLoop().

◆ WalSndErrorCleanup()

void WalSndErrorCleanup ( void  )

Definition at line 334 of file walsender.c.

335{
340
341 if (xlogreader != NULL && xlogreader->seg.ws_file >= 0)
343
344 if (MyReplicationSlot != NULL)
346
348
349 replication_active = false;
350
351 /*
352 * If there is a transaction in progress, it will clean up our
353 * ResourceOwner, but if a replication command set up a resource owner
354 * without a transaction, we've got to clean that up now.
355 */
358
360 proc_exit(0);
361
362 /* Revert back to startup state */
364}
void pgaio_error_cleanup(void)
Definition: aio.c:1162
bool ConditionVariableCancelSleep(void)
void LWLockReleaseAll(void)
Definition: lwlock.c:1945
void ReplicationSlotCleanup(bool synced_only)
Definition: slot.c:820
WALOpenSegment seg
Definition: xlogreader.h:272
static volatile sig_atomic_t got_SIGUSR2
Definition: walsender.c:205
bool IsTransactionOrTransactionBlock(void)
Definition: xact.c:5001

References ConditionVariableCancelSleep(), got_SIGUSR2, got_STOPPING, IsTransactionOrTransactionBlock(), LWLockReleaseAll(), MyReplicationSlot, pgaio_error_cleanup(), pgstat_report_wait_end(), proc_exit(), ReleaseAuxProcessResources(), replication_active, ReplicationSlotCleanup(), ReplicationSlotRelease(), XLogReaderState::seg, wal_segment_close(), WalSndSetState(), WALSNDSTATE_STARTUP, WALOpenSegment::ws_file, and xlogreader.

Referenced by PostgresMain().

◆ WalSndGetStateString()

static const char * WalSndGetStateString ( WalSndState  state)
static

Definition at line 3941 of file walsender.c.

3942{
3943 switch (state)
3944 {
3946 return "startup";
3947 case WALSNDSTATE_BACKUP:
3948 return "backup";
3950 return "catchup";
3952 return "streaming";
3954 return "stopping";
3955 }
3956 return "UNKNOWN";
3957}
@ WALSNDSTATE_STREAMING
@ WALSNDSTATE_BACKUP

References WALSNDSTATE_BACKUP, WALSNDSTATE_CATCHUP, WALSNDSTATE_STARTUP, WALSNDSTATE_STOPPING, and WALSNDSTATE_STREAMING.

Referenced by pg_stat_get_wal_senders().

◆ WalSndInitStopping()

void WalSndInitStopping ( void  )

Definition at line 3858 of file walsender.c.

3859{
3860 int i;
3861
3862 for (i = 0; i < max_wal_senders; i++)
3863 {
3864 WalSnd *walsnd = &WalSndCtl->walsnds[i];
3865 pid_t pid;
3866
3867 SpinLockAcquire(&walsnd->mutex);
3868 pid = walsnd->pid;
3869 SpinLockRelease(&walsnd->mutex);
3870
3871 if (pid == 0)
3872 continue;
3873
3875 }
3876}
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
int SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
Definition: procsignal.c:284
@ PROCSIG_WALSND_INIT_STOPPING
Definition: procsignal.h:35

References i, INVALID_PROC_NUMBER, max_wal_senders, WalSnd::mutex, WalSnd::pid, PROCSIG_WALSND_INIT_STOPPING, SendProcSignal(), SpinLockAcquire, SpinLockRelease, WalSndCtl, and WalSndCtlData::walsnds.

Referenced by ShutdownXLOG().

◆ WalSndKeepalive()

static void WalSndKeepalive ( bool  requestReply,
XLogRecPtr  writePtr 
)
static

Definition at line 4147 of file walsender.c.

4148{
4149 elog(DEBUG2, "sending replication keepalive");
4150
4151 /* construct the message... */
4154 pq_sendint64(&output_message, XLogRecPtrIsInvalid(writePtr) ? sentPtr : writePtr);
4156 pq_sendbyte(&output_message, requestReply ? 1 : 0);
4157
4158 /* ... and send it wrapped in CopyData */
4160
4161 /* Set local flag */
4162 if (requestReply)
4164}
#define PqReplMsg_Keepalive
Definition: protocol.h:75

References StringInfoData::data, DEBUG2, elog, GetCurrentTimestamp(), StringInfoData::len, output_message, pq_putmessage_noblock, pq_sendbyte(), pq_sendint64(), PqMsg_CopyData, PqReplMsg_Keepalive, resetStringInfo(), sentPtr, waiting_for_ping_response, and XLogRecPtrIsInvalid.

Referenced by ProcessStandbyReplyMessage(), WalSndDone(), WalSndKeepaliveIfNecessary(), WalSndUpdateProgress(), and WalSndWaitForWal().

◆ WalSndKeepaliveIfNecessary()

static void WalSndKeepaliveIfNecessary ( void  )
static

Definition at line 4170 of file walsender.c.

4171{
4172 TimestampTz ping_time;
4173
4174 /*
4175 * Don't send keepalive messages if timeouts are globally disabled or
4176 * we're doing something not partaking in timeouts.
4177 */
4179 return;
4180
4182 return;
4183
4184 /*
4185 * If half of wal_sender_timeout has lapsed without receiving any reply
4186 * from the standby, send a keep-alive message to the standby requesting
4187 * an immediate reply.
4188 */
4190 wal_sender_timeout / 2);
4191 if (last_processing >= ping_time)
4192 {
4194
4195 /* Try to flush pending output to the client */
4196 if (pq_flush_if_writable() != 0)
4198 }
4199}

References InvalidXLogRecPtr, last_processing, last_reply_timestamp, pq_flush_if_writable, TimestampTzPlusMilliseconds, waiting_for_ping_response, wal_sender_timeout, WalSndKeepalive(), and WalSndShutdown().

Referenced by ProcessPendingWrites(), WalSndLoop(), and WalSndWaitForWal().

◆ WalSndKill()

static void WalSndKill ( int  code,
Datum  arg 
)
static

Definition at line 3077 of file walsender.c.

3078{
3079 WalSnd *walsnd = MyWalSnd;
3080
3081 Assert(walsnd != NULL);
3082
3083 MyWalSnd = NULL;
3084
3085 SpinLockAcquire(&walsnd->mutex);
3086 /* Mark WalSnd struct as no longer being in use. */
3087 walsnd->pid = 0;
3088 SpinLockRelease(&walsnd->mutex);
3089}

References Assert(), WalSnd::mutex, MyWalSnd, WalSnd::pid, SpinLockAcquire, and SpinLockRelease.

Referenced by InitWalSenderSlot().

◆ WalSndLastCycleHandler()

static void WalSndLastCycleHandler ( SIGNAL_ARGS  )
static

Definition at line 3695 of file walsender.c.

3696{
3697 got_SIGUSR2 = true;
3699}

References got_SIGUSR2, MyLatch, and SetLatch().

Referenced by WalSndSignals().

◆ WalSndLoop()

static void WalSndLoop ( WalSndSendDataCallback  send_data)
static

Definition at line 2859 of file walsender.c.

2860{
2861 TimestampTz last_flush = 0;
2862
2863 /*
2864 * Initialize the last reply timestamp. That enables timeout processing
2865 * from hereon.
2866 */
2869
2870 /*
2871 * Loop until we reach the end of this timeline or the client requests to
2872 * stop streaming.
2873 */
2874 for (;;)
2875 {
2876 /* Clear any already-pending wakeups */
2878
2880
2881 /* Process any requests or signals received recently */
2883 {
2884 ConfigReloadPending = false;
2887 }
2888
2889 /* Check for input from the client */
2891
2892 /*
2893 * If we have received CopyDone from the client, sent CopyDone
2894 * ourselves, and the output buffer is empty, it's time to exit
2895 * streaming.
2896 */
2899 break;
2900
2901 /*
2902 * If we don't have any pending data in the output buffer, try to send
2903 * some more. If there is some, we don't bother to call send_data
2904 * again until we've flushed it ... but we'd better assume we are not
2905 * caught up.
2906 */
2907 if (!pq_is_send_pending())
2908 send_data();
2909 else
2910 WalSndCaughtUp = false;
2911
2912 /* Try to flush pending output to the client */
2913 if (pq_flush_if_writable() != 0)
2915
2916 /* If nothing remains to be sent right now ... */
2918 {
2919 /*
2920 * If we're in catchup state, move to streaming. This is an
2921 * important state change for users to know about, since before
2922 * this point data loss might occur if the primary dies and we
2923 * need to failover to the standby. The state change is also
2924 * important for synchronous replication, since commits that
2925 * started to wait at that point might wait for some time.
2926 */
2928 {
2930 (errmsg_internal("\"%s\" has now caught up with upstream server",
2933 }
2934
2935 /*
2936 * When SIGUSR2 arrives, we send any outstanding logs up to the
2937 * shutdown checkpoint record (i.e., the latest record), wait for
2938 * them to be replicated to the standby, and exit. This may be a
2939 * normal termination at shutdown, or a promotion, the walsender
2940 * is not sure which.
2941 */
2942 if (got_SIGUSR2)
2943 WalSndDone(send_data);
2944 }
2945
2946 /* Check for replication timeout. */
2948
2949 /* Send keepalive if the time has come */
2951
2952 /*
2953 * Block if we have unsent data. XXX For logical replication, let
2954 * WalSndWaitForWal() handle any other blocking; idle receivers need
2955 * its additional actions. For physical replication, also block if
2956 * caught up; its send_data does not block.
2957 *
2958 * The IO statistics are reported in WalSndWaitForWal() for the
2959 * logical WAL senders.
2960 */
2961 if ((WalSndCaughtUp && send_data != XLogSendLogical &&
2964 {
2965 long sleeptime;
2966 int wakeEvents;
2968
2970 wakeEvents = WL_SOCKET_READABLE;
2971 else
2972 wakeEvents = 0;
2973
2974 /*
2975 * Use fresh timestamp, not last_processing, to reduce the chance
2976 * of reaching wal_sender_timeout before sending a keepalive.
2977 */
2979 sleeptime = WalSndComputeSleeptime(now);
2980
2981 if (pq_is_send_pending())
2982 wakeEvents |= WL_SOCKET_WRITEABLE;
2983
2984 /* Report IO statistics, if needed */
2985 if (TimestampDifferenceExceeds(last_flush, now,
2987 {
2988 pgstat_flush_io(false);
2990 last_flush = now;
2991 }
2992
2993 /* Sleep until something happens or we time out */
2994 WalSndWait(wakeEvents, sleeptime, WAIT_EVENT_WAL_SENDER_MAIN);
2995 }
2996 }
2997}
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Definition: timestamp.c:1781
char * application_name
Definition: guc_tables.c:561
bool pgstat_flush_backend(bool nowait, bits32 flags)
#define PGSTAT_BACKEND_FLUSH_IO
void pgstat_flush_io(bool nowait)
Definition: pgstat_io.c:175
#define WALSENDER_STATS_FLUSH_INTERVAL
Definition: walsender.c:103
static void WalSndDone(WalSndSendDataCallback send_data)
Definition: walsender.c:3574

References application_name, CHECK_FOR_INTERRUPTS, ConfigReloadPending, DEBUG1, ereport, errmsg_internal(), GetCurrentTimestamp(), got_SIGUSR2, last_reply_timestamp, MyLatch, MyWalSnd, now(), PGC_SIGHUP, PGSTAT_BACKEND_FLUSH_IO, pgstat_flush_backend(), pgstat_flush_io(), pq_flush_if_writable, pq_is_send_pending, ProcessConfigFile(), ProcessRepliesIfAny(), ResetLatch(), WalSnd::state, streamingDoneReceiving, streamingDoneSending, SyncRepInitConfig(), TimestampDifferenceExceeds(), waiting_for_ping_response, WALSENDER_STATS_FLUSH_INTERVAL, WalSndCaughtUp, WalSndCheckTimeOut(), WalSndComputeSleeptime(), WalSndDone(), WalSndKeepaliveIfNecessary(), WalSndSetState(), WalSndShutdown(), WALSNDSTATE_CATCHUP, WALSNDSTATE_STREAMING, WalSndWait(), WL_SOCKET_READABLE, WL_SOCKET_WRITEABLE, and XLogSendLogical().

Referenced by StartLogicalReplication(), and StartReplication().

◆ WalSndPrepareWrite()

static void WalSndPrepareWrite ( LogicalDecodingContext ctx,
XLogRecPtr  lsn,
TransactionId  xid,
bool  last_write 
)
static

Definition at line 1530 of file walsender.c.

1531{
1532 /* can't have sync rep confused by sending the same LSN several times */
1533 if (!last_write)
1534 lsn = InvalidXLogRecPtr;
1535
1536 resetStringInfo(ctx->out);
1537
1539 pq_sendint64(ctx->out, lsn); /* dataStart */
1540 pq_sendint64(ctx->out, lsn); /* walEnd */
1541
1542 /*
1543 * Fill out the sendtime later, just as it's done in XLogSendPhysical, but
1544 * reserve space here.
1545 */
1546 pq_sendint64(ctx->out, 0); /* sendtime */
1547}
#define PqReplMsg_WALData
Definition: protocol.h:77
StringInfo out
Definition: logical.h:71

References InvalidXLogRecPtr, LogicalDecodingContext::out, pq_sendbyte(), pq_sendint64(), PqReplMsg_WALData, and resetStringInfo().

Referenced by CreateReplicationSlot(), and StartLogicalReplication().

◆ WalSndRqstFileReload()

void WalSndRqstFileReload ( void  )

Definition at line 3650 of file walsender.c.

3651{
3652 int i;
3653
3654 for (i = 0; i < max_wal_senders; i++)
3655 {
3656 WalSnd *walsnd = &WalSndCtl->walsnds[i];
3657
3658 SpinLockAcquire(&walsnd->mutex);
3659 if (walsnd->pid == 0)
3660 {
3661 SpinLockRelease(&walsnd->mutex);
3662 continue;
3663 }
3664 walsnd->needreload = true;
3665 SpinLockRelease(&walsnd->mutex);
3666 }
3667}

References i, max_wal_senders, WalSnd::mutex, WalSnd::needreload, WalSnd::pid, SpinLockAcquire, SpinLockRelease, WalSndCtl, and WalSndCtlData::walsnds.

Referenced by KeepFileRestoredFromArchive().

◆ WalSndSegmentOpen()

static void WalSndSegmentOpen ( XLogReaderState state,
XLogSegNo  nextSegNo,
TimeLineID tli_p 
)
static

Definition at line 3093 of file walsender.c.

3095{
3096 char path[MAXPGPATH];
3097
3098 /*-------
3099 * When reading from a historic timeline, and there is a timeline switch
3100 * within this segment, read from the WAL segment belonging to the new
3101 * timeline.
3102 *
3103 * For example, imagine that this server is currently on timeline 5, and
3104 * we're streaming timeline 4. The switch from timeline 4 to 5 happened at
3105 * 0/13002088. In pg_wal, we have these files:
3106 *
3107 * ...
3108 * 000000040000000000000012
3109 * 000000040000000000000013
3110 * 000000050000000000000013
3111 * 000000050000000000000014
3112 * ...
3113 *
3114 * In this situation, when requested to send the WAL from segment 0x13, on
3115 * timeline 4, we read the WAL from file 000000050000000000000013. Archive
3116 * recovery prefers files from newer timelines, so if the segment was
3117 * restored from the archive on this server, the file belonging to the old
3118 * timeline, 000000040000000000000013, might not exist. Their contents are
3119 * equal up to the switchpoint, because at a timeline switch, the used
3120 * portion of the old segment is copied to the new file.
3121 */
3122 *tli_p = sendTimeLine;
3124 {
3125 XLogSegNo endSegNo;
3126
3127 XLByteToSeg(sendTimeLineValidUpto, endSegNo, state->segcxt.ws_segsize);
3128 if (nextSegNo == endSegNo)
3129 *tli_p = sendTimeLineNextTLI;
3130 }
3131
3132 XLogFilePath(path, *tli_p, nextSegNo, state->segcxt.ws_segsize);
3133 state->seg.ws_file = BasicOpenFile(path, O_RDONLY | PG_BINARY);
3134 if (state->seg.ws_file >= 0)
3135 return;
3136
3137 /*
3138 * If the file is not found, assume it's because the standby asked for a
3139 * too old WAL segment that has already been removed or recycled.
3140 */
3141 if (errno == ENOENT)
3142 {
3143 char xlogfname[MAXFNAMELEN];
3144 int save_errno = errno;
3145
3146 XLogFileName(xlogfname, *tli_p, nextSegNo, wal_segment_size);
3147 errno = save_errno;
3148 ereport(ERROR,
3150 errmsg("requested WAL segment %s has already been removed",
3151 xlogfname)));
3152 }
3153 else
3154 ereport(ERROR,
3156 errmsg("could not open file \"%s\": %m",
3157 path)));
3158}
int BasicOpenFile(const char *fileName, int fileFlags)
Definition: fd.c:1086
static void XLogFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
static void XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)

References BasicOpenFile(), ereport, errcode_for_file_access(), errmsg(), ERROR, MAXFNAMELEN, MAXPGPATH, PG_BINARY, sendTimeLine, sendTimeLineIsHistoric, sendTimeLineNextTLI, sendTimeLineValidUpto, wal_segment_size, XLByteToSeg, XLogFileName(), and XLogFilePath().

Referenced by CreateReplicationSlot(), StartLogicalReplication(), and StartReplication().

◆ WalSndSetState()

void WalSndSetState ( WalSndState  state)

Definition at line 3922 of file walsender.c.

3923{
3924 WalSnd *walsnd = MyWalSnd;
3925
3927
3928 if (walsnd->state == state)
3929 return;
3930
3931 SpinLockAcquire(&walsnd->mutex);
3932 walsnd->state = state;
3933 SpinLockRelease(&walsnd->mutex);
3934}

References am_walsender, Assert(), WalSnd::mutex, MyWalSnd, SpinLockAcquire, SpinLockRelease, and WalSnd::state.

Referenced by exec_replication_command(), SendBaseBackup(), StartLogicalReplication(), StartReplication(), WalSndErrorCleanup(), WalSndLoop(), and XLogSendPhysical().

◆ WalSndShmemInit()

void WalSndShmemInit ( void  )

Definition at line 3734 of file walsender.c.

3735{
3736 bool found;
3737 int i;
3738
3740 ShmemInitStruct("Wal Sender Ctl", WalSndShmemSize(), &found);
3741
3742 if (!found)
3743 {
3744 /* First time through, so initialize */
3746
3747 for (i = 0; i < NUM_SYNC_REP_WAIT_MODE; i++)
3749
3750 for (i = 0; i < max_wal_senders; i++)
3751 {
3752 WalSnd *walsnd = &WalSndCtl->walsnds[i];
3753
3754 SpinLockInit(&walsnd->mutex);
3755 }
3756
3760 }
3761}
void ConditionVariableInit(ConditionVariable *cv)
static void dlist_init(dlist_head *head)
Definition: ilist.h:314
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
#define SpinLockInit(lock)
Definition: spin.h:57
ConditionVariable wal_replay_cv
dlist_head SyncRepQueue[NUM_SYNC_REP_WAIT_MODE]
ConditionVariable wal_flush_cv
Size WalSndShmemSize(void)
Definition: walsender.c:3722

References ConditionVariableInit(), dlist_init(), i, max_wal_senders, MemSet, WalSnd::mutex, NUM_SYNC_REP_WAIT_MODE, ShmemInitStruct(), SpinLockInit, WalSndCtlData::SyncRepQueue, WalSndCtlData::wal_confirm_rcv_cv, WalSndCtlData::wal_flush_cv, WalSndCtlData::wal_replay_cv, WalSndCtl, WalSndCtlData::walsnds, and WalSndShmemSize().

Referenced by CreateOrAttachShmemStructs().

◆ WalSndShmemSize()

Size WalSndShmemSize ( void  )

Definition at line 3722 of file walsender.c.

3723{
3724 Size size = 0;
3725
3726 size = offsetof(WalSndCtlData, walsnds);
3727 size = add_size(size, mul_size(max_wal_senders, sizeof(WalSnd)));
3728
3729 return size;
3730}
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510

References add_size(), max_wal_senders, and mul_size().

Referenced by CalculateShmemSize(), and WalSndShmemInit().

◆ WalSndShutdown()

static void WalSndShutdown ( void  )
static

Definition at line 370 of file walsender.c.

371{
372 /*
373 * Reset whereToSendOutput to prevent ereport from attempting to send any
374 * more messages to the standby.
375 */
378
379 proc_exit(0);
380 abort(); /* keep the compiler quiet */
381}
@ DestNone
Definition: dest.h:87
CommandDest whereToSendOutput
Definition: postgres.c:91

References DestNone, DestRemote, proc_exit(), and whereToSendOutput.

Referenced by ProcessPendingWrites(), WalSndCheckTimeOut(), WalSndKeepaliveIfNecessary(), WalSndLoop(), WalSndUpdateProgress(), WalSndWaitForWal(), and WalSndWriteData().

◆ WalSndSignals()

void WalSndSignals ( void  )

Definition at line 3703 of file walsender.c.

3704{
3705 /* Set up signal handlers */
3707 pqsignal(SIGINT, StatementCancelHandler); /* query cancel */
3708 pqsignal(SIGTERM, die); /* request shutdown */
3709 /* SIGQUIT handler was already set up by InitPostmasterChild */
3710 InitializeTimeouts(); /* establishes SIGALRM handler */
3711 pqsignal(SIGPIPE, SIG_IGN);
3713 pqsignal(SIGUSR2, WalSndLastCycleHandler); /* request a last cycle and
3714 * shutdown */
3715
3716 /* Reset some signals that are accepted by postmaster but not here */
3717 pqsignal(SIGCHLD, SIG_DFL);
3718}
void SignalHandlerForConfigReload(SIGNAL_ARGS)
Definition: interrupt.c:61
#define die(msg)
#define pqsignal
Definition: port.h:531
void StatementCancelHandler(SIGNAL_ARGS)
Definition: postgres.c:3061
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Definition: procsignal.c:674
void InitializeTimeouts(void)
Definition: timeout.c:470
static void WalSndLastCycleHandler(SIGNAL_ARGS)
Definition: walsender.c:3695
#define SIGCHLD
Definition: win32_port.h:168
#define SIGHUP
Definition: win32_port.h:158
#define SIGPIPE
Definition: win32_port.h:163
#define SIGUSR1
Definition: win32_port.h:170
#define SIGUSR2
Definition: win32_port.h:171

References die, InitializeTimeouts(), pqsignal, procsignal_sigusr1_handler(), SIGCHLD, SIGHUP, SignalHandlerForConfigReload(), SIGPIPE, SIGUSR1, SIGUSR2, StatementCancelHandler(), and WalSndLastCycleHandler().

Referenced by PostgresMain().

◆ WalSndUpdateProgress()

static void WalSndUpdateProgress ( LogicalDecodingContext ctx,
XLogRecPtr  lsn,
TransactionId  xid,
bool  skipped_xact 
)
static

Definition at line 1653 of file walsender.c.

1655{
1656 static TimestampTz sendTime = 0;
1658 bool pending_writes = false;
1659 bool end_xact = ctx->end_xact;
1660
1661 /*
1662 * Track lag no more than once per WALSND_LOGICAL_LAG_TRACK_INTERVAL_MS to
1663 * avoid flooding the lag tracker when we commit frequently.
1664 *
1665 * We don't have a mechanism to get the ack for any LSN other than end
1666 * xact LSN from the downstream. So, we track lag only for end of
1667 * transaction LSN.
1668 */
1669#define WALSND_LOGICAL_LAG_TRACK_INTERVAL_MS 1000
1670 if (end_xact && TimestampDifferenceExceeds(sendTime, now,
1672 {
1673 LagTrackerWrite(lsn, now);
1674 sendTime = now;
1675 }
1676
1677 /*
1678 * When skipping empty transactions in synchronous replication, we send a
1679 * keepalive message to avoid delaying such transactions.
1680 *
1681 * It is okay to check sync_standbys_status without lock here as in the
1682 * worst case we will just send an extra keepalive message when it is
1683 * really not required.
1684 */
1685 if (skipped_xact &&
1686 SyncRepRequested() &&
1687 (((volatile WalSndCtlData *) WalSndCtl)->sync_standbys_status & SYNC_STANDBY_DEFINED))
1688 {
1689 WalSndKeepalive(false, lsn);
1690
1691 /* Try to flush pending output to the client */
1692 if (pq_flush_if_writable() != 0)
1694
1695 /* If we have pending write here, make sure it's actually flushed */
1696 if (pq_is_send_pending())
1697 pending_writes = true;
1698 }
1699
1700 /*
1701 * Process pending writes if any or try to send a keepalive if required.
1702 * We don't need to try sending keep alive messages at the transaction end
1703 * as that will be done at a later point in time. This is required only
1704 * for large transactions where we don't send any changes to the
1705 * downstream and the receiver can timeout due to that.
1706 */
1707 if (pending_writes || (!end_xact &&
1709 wal_sender_timeout / 2)))
1711}
#define SyncRepRequested()
Definition: syncrep.h:18
static void ProcessPendingWrites(void)
Definition: walsender.c:1599
#define WALSND_LOGICAL_LAG_TRACK_INTERVAL_MS
static void LagTrackerWrite(XLogRecPtr lsn, TimestampTz local_flush_time)
Definition: walsender.c:4208
#define SYNC_STANDBY_DEFINED

References LogicalDecodingContext::end_xact, GetCurrentTimestamp(), LagTrackerWrite(), last_reply_timestamp, now(), pq_flush_if_writable, pq_is_send_pending, ProcessPendingWrites(), SYNC_STANDBY_DEFINED, SyncRepRequested, TimestampDifferenceExceeds(), TimestampTzPlusMilliseconds, wal_sender_timeout, WALSND_LOGICAL_LAG_TRACK_INTERVAL_MS, WalSndCtl, WalSndKeepalive(), and WalSndShutdown().

Referenced by CreateReplicationSlot(), and StartLogicalReplication().

◆ WalSndWait()

static void WalSndWait ( uint32  socket_events,
long  timeout,
uint32  wait_event 
)
static

Definition at line 3800 of file walsender.c.

3801{
3802 WaitEvent event;
3803
3804 ModifyWaitEvent(FeBeWaitSet, FeBeWaitSetSocketPos, socket_events, NULL);
3805
3806 /*
3807 * We use a condition variable to efficiently wake up walsenders in
3808 * WalSndWakeup().
3809 *
3810 * Every walsender prepares to sleep on a shared memory CV. Note that it
3811 * just prepares to sleep on the CV (i.e., adds itself to the CV's
3812 * waitlist), but does not actually wait on the CV (IOW, it never calls
3813 * ConditionVariableSleep()). It still uses WaitEventSetWait() for
3814 * waiting, because we also need to wait for socket events. The processes
3815 * (startup process, walreceiver etc.) wanting to wake up walsenders use
3816 * ConditionVariableBroadcast(), which in turn calls SetLatch(), helping
3817 * walsenders come out of WaitEventSetWait().
3818 *
3819 * This approach is simple and efficient because, one doesn't have to loop
3820 * through all the walsenders slots, with a spinlock acquisition and
3821 * release for every iteration, just to wake up only the waiting
3822 * walsenders. It makes WalSndWakeup() callers' life easy.
3823 *
3824 * XXX: A desirable future improvement would be to add support for CVs
3825 * into WaitEventSetWait().
3826 *
3827 * And, we use separate shared memory CVs for physical and logical
3828 * walsenders for selective wake ups, see WalSndWakeup() for more details.
3829 *
3830 * If the wait event is WAIT_FOR_STANDBY_CONFIRMATION, wait on another CV
3831 * until awakened by physical walsenders after the walreceiver confirms
3832 * the receipt of the LSN.
3833 */
3834 if (wait_event == WAIT_EVENT_WAIT_FOR_STANDBY_CONFIRMATION)
3840
3841 if (WaitEventSetWait(FeBeWaitSet, timeout, &event, 1, wait_event) == 1 &&
3842 (event.events & WL_POSTMASTER_DEATH))
3843 {
3845 proc_exit(1);
3846 }
3847
3849}
void ConditionVariablePrepareToSleep(ConditionVariable *cv)
#define FeBeWaitSetSocketPos
Definition: libpq.h:63
WaitEventSet * FeBeWaitSet
Definition: pqcomm.c:166
uint32 events
Definition: waiteventset.h:62
void ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch)
Definition: waiteventset.c:656
int WaitEventSetWait(WaitEventSet *set, long timeout, WaitEvent *occurred_events, int nevents, uint32 wait_event_info)
#define WL_POSTMASTER_DEATH
Definition: waiteventset.h:38

References ConditionVariableCancelSleep(), ConditionVariablePrepareToSleep(), WaitEvent::events, FeBeWaitSet, FeBeWaitSetSocketPos, WalSnd::kind, ModifyWaitEvent(), MyWalSnd, proc_exit(), REPLICATION_KIND_LOGICAL, REPLICATION_KIND_PHYSICAL, WaitEventSetWait(), WalSndCtlData::wal_confirm_rcv_cv, WalSndCtlData::wal_flush_cv, WalSndCtlData::wal_replay_cv, WalSndCtl, and WL_POSTMASTER_DEATH.

Referenced by ProcessPendingWrites(), WalSndLoop(), and WalSndWaitForWal().

◆ WalSndWaitForWal()

static XLogRecPtr WalSndWaitForWal ( XLogRecPtr  loc)
static

Definition at line 1803 of file walsender.c.

1804{
1805 int wakeEvents;
1806 uint32 wait_event = 0;
1807 static XLogRecPtr RecentFlushPtr = InvalidXLogRecPtr;
1808 TimestampTz last_flush = 0;
1809
1810 /*
1811 * Fast path to avoid acquiring the spinlock in case we already know we
1812 * have enough WAL available and all the standby servers have confirmed
1813 * receipt of WAL up to RecentFlushPtr. This is particularly interesting
1814 * if we're far behind.
1815 */
1816 if (!XLogRecPtrIsInvalid(RecentFlushPtr) &&
1817 !NeedToWaitForWal(loc, RecentFlushPtr, &wait_event))
1818 return RecentFlushPtr;
1819
1820 /*
1821 * Within the loop, we wait for the necessary WALs to be flushed to disk
1822 * first, followed by waiting for standbys to catch up if there are enough
1823 * WALs (see NeedToWaitForWal()) or upon receiving the shutdown signal.
1824 */
1825 for (;;)
1826 {
1827 bool wait_for_standby_at_stop = false;
1828 long sleeptime;
1830
1831 /* Clear any already-pending wakeups */
1833
1835
1836 /* Process any requests or signals received recently */
1838 {
1839 ConfigReloadPending = false;
1842 }
1843
1844 /* Check for input from the client */
1846
1847 /*
1848 * If we're shutting down, trigger pending WAL to be written out,
1849 * otherwise we'd possibly end up waiting for WAL that never gets
1850 * written, because walwriter has shut down already.
1851 */
1852 if (got_STOPPING)
1854
1855 /*
1856 * To avoid the scenario where standbys need to catch up to a newer
1857 * WAL location in each iteration, we update our idea of the currently
1858 * flushed position only if we are not waiting for standbys to catch
1859 * up.
1860 */
1861 if (wait_event != WAIT_EVENT_WAIT_FOR_STANDBY_CONFIRMATION)
1862 {
1863 if (!RecoveryInProgress())
1864 RecentFlushPtr = GetFlushRecPtr(NULL);
1865 else
1866 RecentFlushPtr = GetXLogReplayRecPtr(NULL);
1867 }
1868
1869 /*
1870 * If postmaster asked us to stop and the standby slots have caught up
1871 * to the flushed position, don't wait anymore.
1872 *
1873 * It's important to do this check after the recomputation of
1874 * RecentFlushPtr, so we can send all remaining data before shutting
1875 * down.
1876 */
1877 if (got_STOPPING)
1878 {
1879 if (NeedToWaitForStandbys(RecentFlushPtr, &wait_event))
1880 wait_for_standby_at_stop = true;
1881 else
1882 break;
1883 }
1884
1885 /*
1886 * We only send regular messages to the client for full decoded
1887 * transactions, but a synchronous replication and walsender shutdown
1888 * possibly are waiting for a later location. So, before sleeping, we
1889 * send a ping containing the flush location. If the receiver is
1890 * otherwise idle, this keepalive will trigger a reply. Processing the
1891 * reply will update these MyWalSnd locations.
1892 */
1893 if (MyWalSnd->flush < sentPtr &&
1894 MyWalSnd->write < sentPtr &&
1897
1898 /*
1899 * Exit the loop if already caught up and doesn't need to wait for
1900 * standby slots.
1901 */
1902 if (!wait_for_standby_at_stop &&
1903 !NeedToWaitForWal(loc, RecentFlushPtr, &wait_event))
1904 break;
1905
1906 /*
1907 * Waiting for new WAL or waiting for standbys to catch up. Since we
1908 * need to wait, we're now caught up.
1909 */
1910 WalSndCaughtUp = true;
1911
1912 /*
1913 * Try to flush any pending output to the client.
1914 */
1915 if (pq_flush_if_writable() != 0)
1917
1918 /*
1919 * If we have received CopyDone from the client, sent CopyDone
1920 * ourselves, and the output buffer is empty, it's time to exit
1921 * streaming, so fail the current WAL fetch request.
1922 */
1925 break;
1926
1927 /* die if timeout was reached */
1929
1930 /* Send keepalive if the time has come */
1932
1933 /*
1934 * Sleep until something happens or we time out. Also wait for the
1935 * socket becoming writable, if there's still pending output.
1936 * Otherwise we might sit on sendable output data while waiting for
1937 * new WAL to be generated. (But if we have nothing to send, we don't
1938 * want to wake on socket-writable.)
1939 */
1941 sleeptime = WalSndComputeSleeptime(now);
1942
1943 wakeEvents = WL_SOCKET_READABLE;
1944
1945 if (pq_is_send_pending())
1946 wakeEvents |= WL_SOCKET_WRITEABLE;
1947
1948 Assert(wait_event != 0);
1949
1950 /* Report IO statistics, if needed */
1951 if (TimestampDifferenceExceeds(last_flush, now,
1953 {
1954 pgstat_flush_io(false);
1956 last_flush = now;
1957 }
1958
1959 WalSndWait(wakeEvents, sleeptime, wait_event);
1960 }
1961
1962 /* reactivate latch so WalSndLoop knows to continue */
1964 return RecentFlushPtr;
1965}
static bool NeedToWaitForWal(XLogRecPtr target_lsn, XLogRecPtr flushed_lsn, uint32 *wait_event)
Definition: walsender.c:1775
bool XLogBackgroundFlush(void)
Definition: xlog.c:2975

References Assert(), CHECK_FOR_INTERRUPTS, ConfigReloadPending, WalSnd::flush, GetCurrentTimestamp(), GetFlushRecPtr(), GetXLogReplayRecPtr(), got_STOPPING, InvalidXLogRecPtr, MyLatch, MyWalSnd, NeedToWaitForStandbys(), NeedToWaitForWal(), now(), PGC_SIGHUP, PGSTAT_BACKEND_FLUSH_IO, pgstat_flush_backend(), pgstat_flush_io(), pq_flush_if_writable, pq_is_send_pending, ProcessConfigFile(), ProcessRepliesIfAny(), RecoveryInProgress(), ResetLatch(), sentPtr, SetLatch(), streamingDoneReceiving, streamingDoneSending, SyncRepInitConfig(), TimestampDifferenceExceeds(), waiting_for_ping_response, WALSENDER_STATS_FLUSH_INTERVAL, WalSndCaughtUp, WalSndCheckTimeOut(), WalSndComputeSleeptime(), WalSndKeepalive(), WalSndKeepaliveIfNecessary(), WalSndShutdown(), WalSndWait(), WL_SOCKET_READABLE, WL_SOCKET_WRITEABLE, WalSnd::write, XLogBackgroundFlush(), and XLogRecPtrIsInvalid.

Referenced by logical_read_xlog_page().

◆ WalSndWaitStopping()

void WalSndWaitStopping ( void  )

Definition at line 3884 of file walsender.c.

3885{
3886 for (;;)
3887 {
3888 int i;
3889 bool all_stopped = true;
3890
3891 for (i = 0; i < max_wal_senders; i++)
3892 {
3893 WalSnd *walsnd = &WalSndCtl->walsnds[i];
3894
3895 SpinLockAcquire(&walsnd->mutex);
3896
3897 if (walsnd->pid == 0)
3898 {
3899 SpinLockRelease(&walsnd->mutex);
3900 continue;
3901 }
3902
3903 if (walsnd->state != WALSNDSTATE_STOPPING)
3904 {
3905 all_stopped = false;
3906 SpinLockRelease(&walsnd->mutex);
3907 break;
3908 }
3909 SpinLockRelease(&walsnd->mutex);
3910 }
3911
3912 /* safe to leave if confirmation is done for all WAL senders */
3913 if (all_stopped)
3914 return;
3915
3916 pg_usleep(10000L); /* wait for 10 msec */
3917 }
3918}
void pg_usleep(long microsec)
Definition: signal.c:53

References i, max_wal_senders, WalSnd::mutex, pg_usleep(), WalSnd::pid, SpinLockAcquire, SpinLockRelease, WalSnd::state, WalSndCtl, WalSndCtlData::walsnds, and WALSNDSTATE_STOPPING.

Referenced by ShutdownXLOG().

◆ WalSndWakeup()

void WalSndWakeup ( bool  physical,
bool  logical 
)

Definition at line 3779 of file walsender.c.

3780{
3781 /*
3782 * Wake up all the walsenders waiting on WAL being flushed or replayed
3783 * respectively. Note that waiting walsender would have prepared to sleep
3784 * on the CV (i.e., added itself to the CV's waitlist) in WalSndWait()
3785 * before actually waiting.
3786 */
3787 if (physical)
3789
3790 if (logical)
3792}

References ConditionVariableBroadcast(), WalSndCtlData::wal_flush_cv, WalSndCtlData::wal_replay_cv, and WalSndCtl.

Referenced by ApplyWalRecord(), KeepFileRestoredFromArchive(), StartupXLOG(), WalSndWakeupProcessRequests(), and XLogWalRcvFlush().

◆ WalSndWriteData()

static void WalSndWriteData ( LogicalDecodingContext ctx,
XLogRecPtr  lsn,
TransactionId  xid,
bool  last_write 
)
static

Definition at line 1557 of file walsender.c.

1559{
1561
1562 /*
1563 * Fill the send timestamp last, so that it is taken as late as possible.
1564 * This is somewhat ugly, but the protocol is set as it's already used for
1565 * several releases by streaming physical replication.
1566 */
1570 memcpy(&ctx->out->data[1 + sizeof(int64) + sizeof(int64)],
1571 tmpbuf.data, sizeof(int64));
1572
1573 /* output previously gathered data in a CopyData packet */
1575
1577
1578 /* Try to flush pending output to the client */
1579 if (pq_flush_if_writable() != 0)
1581
1582 /* Try taking fast path unless we get too close to walsender timeout. */
1584 wal_sender_timeout / 2) &&
1586 {
1587 return;
1588 }
1589
1590 /* If we have pending write here, go to slow path */
1592}

References CHECK_FOR_INTERRUPTS, StringInfoData::data, GetCurrentTimestamp(), last_reply_timestamp, StringInfoData::len, now(), LogicalDecodingContext::out, pq_flush_if_writable, pq_is_send_pending, pq_putmessage_noblock, pq_sendint64(), PqMsg_CopyData, ProcessPendingWrites(), resetStringInfo(), TimestampTzPlusMilliseconds, tmpbuf, wal_sender_timeout, and WalSndShutdown().

Referenced by CreateReplicationSlot(), and StartLogicalReplication().

◆ XLogSendLogical()

static void XLogSendLogical ( void  )
static

Definition at line 3481 of file walsender.c.

3482{
3483 XLogRecord *record;
3484 char *errm;
3485
3486 /*
3487 * We'll use the current flush point to determine whether we've caught up.
3488 * This variable is static in order to cache it across calls. Caching is
3489 * helpful because GetFlushRecPtr() needs to acquire a heavily-contended
3490 * spinlock.
3491 */
3492 static XLogRecPtr flushPtr = InvalidXLogRecPtr;
3493
3494 /*
3495 * Don't know whether we've caught up yet. We'll set WalSndCaughtUp to
3496 * true in WalSndWaitForWal, if we're actually waiting. We also set to
3497 * true if XLogReadRecord() had to stop reading but WalSndWaitForWal
3498 * didn't wait - i.e. when we're shutting down.
3499 */
3500 WalSndCaughtUp = false;
3501
3502 record = XLogReadRecord(logical_decoding_ctx->reader, &errm);
3503
3504 /* xlog record was invalid */
3505 if (errm != NULL)
3506 elog(ERROR, "could not find record while sending logically-decoded data: %s",
3507 errm);
3508
3509 if (record != NULL)
3510 {
3511 /*
3512 * Note the lack of any call to LagTrackerWrite() which is handled by
3513 * WalSndUpdateProgress which is called by output plugin through
3514 * logical decoding write api.
3515 */
3517
3519 }
3520
3521 /*
3522 * If first time through in this session, initialize flushPtr. Otherwise,
3523 * we only need to update flushPtr if EndRecPtr is past it.
3524 */
3525 if (flushPtr == InvalidXLogRecPtr ||
3527 {
3528 /*
3529 * For cascading logical WAL senders, we use the replay LSN instead of
3530 * the flush LSN, since logical decoding on a standby only processes
3531 * WAL that has been replayed. This distinction becomes particularly
3532 * important during shutdown, as new WAL is no longer replayed and the
3533 * last replayed LSN marks the furthest point up to which decoding can
3534 * proceed.
3535 */
3537 flushPtr = GetXLogReplayRecPtr(NULL);
3538 else
3539 flushPtr = GetFlushRecPtr(NULL);
3540 }
3541
3542 /* If EndRecPtr is still past our flushPtr, it means we caught up. */
3543 if (logical_decoding_ctx->reader->EndRecPtr >= flushPtr)
3544 WalSndCaughtUp = true;
3545
3546 /*
3547 * If we're caught up and have been requested to stop, have WalSndLoop()
3548 * terminate the connection in an orderly manner, after writing out all
3549 * the pending data.
3550 */
3552 got_SIGUSR2 = true;
3553
3554 /* Update shared memory status */
3555 {
3556 WalSnd *walsnd = MyWalSnd;
3557
3558 SpinLockAcquire(&walsnd->mutex);
3559 walsnd->sentPtr = sentPtr;
3560 SpinLockRelease(&walsnd->mutex);
3561 }
3562}
void LogicalDecodingProcessRecord(LogicalDecodingContext *ctx, XLogReaderState *record)
Definition: decode.c:88
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
XLogRecord * XLogReadRecord(XLogReaderState *state, char **errormsg)
Definition: xlogreader.c:390

References am_cascading_walsender, elog, XLogReaderState::EndRecPtr, ERROR, GetFlushRecPtr(), GetXLogReplayRecPtr(), got_SIGUSR2, got_STOPPING, InvalidXLogRecPtr, logical_decoding_ctx, LogicalDecodingProcessRecord(), WalSnd::mutex, MyWalSnd, LogicalDecodingContext::reader, sentPtr, WalSnd::sentPtr, SpinLockAcquire, SpinLockRelease, WalSndCaughtUp, and XLogReadRecord().

Referenced by StartLogicalReplication(), and WalSndLoop().

◆ XLogSendPhysical()

static void XLogSendPhysical ( void  )
static

Definition at line 3171 of file walsender.c.

3172{
3173 XLogRecPtr SendRqstPtr;
3174 XLogRecPtr startptr;
3175 XLogRecPtr endptr;
3176 Size nbytes;
3177 XLogSegNo segno;
3178 WALReadError errinfo;
3179 Size rbytes;
3180
3181 /* If requested switch the WAL sender to the stopping state. */
3182 if (got_STOPPING)
3184
3186 {
3187 WalSndCaughtUp = true;
3188 return;
3189 }
3190
3191 /* Figure out how far we can safely send the WAL. */
3193 {
3194 /*
3195 * Streaming an old timeline that's in this server's history, but is
3196 * not the one we're currently inserting or replaying. It can be
3197 * streamed up to the point where we switched off that timeline.
3198 */
3199 SendRqstPtr = sendTimeLineValidUpto;
3200 }
3201 else if (am_cascading_walsender)
3202 {
3203 TimeLineID SendRqstTLI;
3204
3205 /*
3206 * Streaming the latest timeline on a standby.
3207 *
3208 * Attempt to send all WAL that has already been replayed, so that we
3209 * know it's valid. If we're receiving WAL through streaming
3210 * replication, it's also OK to send any WAL that has been received
3211 * but not replayed.
3212 *
3213 * The timeline we're recovering from can change, or we can be
3214 * promoted. In either case, the current timeline becomes historic. We
3215 * need to detect that so that we don't try to stream past the point
3216 * where we switched to another timeline. We check for promotion or
3217 * timeline switch after calculating FlushPtr, to avoid a race
3218 * condition: if the timeline becomes historic just after we checked
3219 * that it was still current, it's still be OK to stream it up to the
3220 * FlushPtr that was calculated before it became historic.
3221 */
3222 bool becameHistoric = false;
3223
3224 SendRqstPtr = GetStandbyFlushRecPtr(&SendRqstTLI);
3225
3226 if (!RecoveryInProgress())
3227 {
3228 /* We have been promoted. */
3229 SendRqstTLI = GetWALInsertionTimeLine();
3230 am_cascading_walsender = false;
3231 becameHistoric = true;
3232 }
3233 else
3234 {
3235 /*
3236 * Still a cascading standby. But is the timeline we're sending
3237 * still the one recovery is recovering from?
3238 */
3239 if (sendTimeLine != SendRqstTLI)
3240 becameHistoric = true;
3241 }
3242
3243 if (becameHistoric)
3244 {
3245 /*
3246 * The timeline we were sending has become historic. Read the
3247 * timeline history file of the new timeline to see where exactly
3248 * we forked off from the timeline we were sending.
3249 */
3250 List *history;
3251
3252 history = readTimeLineHistory(SendRqstTLI);
3254
3256 list_free_deep(history);
3257
3259
3260 SendRqstPtr = sendTimeLineValidUpto;
3261 }
3262 }
3263 else
3264 {
3265 /*
3266 * Streaming the current timeline on a primary.
3267 *
3268 * Attempt to send all data that's already been written out and
3269 * fsync'd to disk. We cannot go further than what's been written out
3270 * given the current implementation of WALRead(). And in any case
3271 * it's unsafe to send WAL that is not securely down to disk on the
3272 * primary: if the primary subsequently crashes and restarts, standbys
3273 * must not have applied any WAL that got lost on the primary.
3274 */
3275 SendRqstPtr = GetFlushRecPtr(NULL);
3276 }
3277
3278 /*
3279 * Record the current system time as an approximation of the time at which
3280 * this WAL location was written for the purposes of lag tracking.
3281 *
3282 * In theory we could make XLogFlush() record a time in shmem whenever WAL
3283 * is flushed and we could get that time as well as the LSN when we call
3284 * GetFlushRecPtr() above (and likewise for the cascading standby
3285 * equivalent), but rather than putting any new code into the hot WAL path
3286 * it seems good enough to capture the time here. We should reach this
3287 * after XLogFlush() runs WalSndWakeupProcessRequests(), and although that
3288 * may take some time, we read the WAL flush pointer and take the time
3289 * very close to together here so that we'll get a later position if it is
3290 * still moving.
3291 *
3292 * Because LagTrackerWrite ignores samples when the LSN hasn't advanced,
3293 * this gives us a cheap approximation for the WAL flush time for this
3294 * LSN.
3295 *
3296 * Note that the LSN is not necessarily the LSN for the data contained in
3297 * the present message; it's the end of the WAL, which might be further
3298 * ahead. All the lag tracking machinery cares about is finding out when
3299 * that arbitrary LSN is eventually reported as written, flushed and
3300 * applied, so that it can measure the elapsed time.
3301 */
3302 LagTrackerWrite(SendRqstPtr, GetCurrentTimestamp());
3303
3304 /*
3305 * If this is a historic timeline and we've reached the point where we
3306 * forked to the next timeline, stop streaming.
3307 *
3308 * Note: We might already have sent WAL > sendTimeLineValidUpto. The
3309 * startup process will normally replay all WAL that has been received
3310 * from the primary, before promoting, but if the WAL streaming is
3311 * terminated at a WAL page boundary, the valid portion of the timeline
3312 * might end in the middle of a WAL record. We might've already sent the
3313 * first half of that partial WAL record to the cascading standby, so that
3314 * sentPtr > sendTimeLineValidUpto. That's OK; the cascading standby can't
3315 * replay the partial WAL record either, so it can still follow our
3316 * timeline switch.
3317 */
3319 {
3320 /* close the current file. */
3321 if (xlogreader->seg.ws_file >= 0)
3323
3324 /* Send CopyDone */
3326 streamingDoneSending = true;
3327
3328 WalSndCaughtUp = true;
3329
3330 elog(DEBUG1, "walsender reached end of timeline at %X/%08X (sent up to %X/%08X)",
3333 return;
3334 }
3335
3336 /* Do we have any work to do? */
3337 Assert(sentPtr <= SendRqstPtr);
3338 if (SendRqstPtr <= sentPtr)
3339 {
3340 WalSndCaughtUp = true;
3341 return;
3342 }
3343
3344 /*
3345 * Figure out how much to send in one message. If there's no more than
3346 * MAX_SEND_SIZE bytes to send, send everything. Otherwise send
3347 * MAX_SEND_SIZE bytes, but round back to logfile or page boundary.
3348 *
3349 * The rounding is not only for performance reasons. Walreceiver relies on
3350 * the fact that we never split a WAL record across two messages. Since a
3351 * long WAL record is split at page boundary into continuation records,
3352 * page boundary is always a safe cut-off point. We also assume that
3353 * SendRqstPtr never points to the middle of a WAL record.
3354 */
3355 startptr = sentPtr;
3356 endptr = startptr;
3357 endptr += MAX_SEND_SIZE;
3358
3359 /* if we went beyond SendRqstPtr, back off */
3360 if (SendRqstPtr <= endptr)
3361 {
3362 endptr = SendRqstPtr;
3364 WalSndCaughtUp = false;
3365 else
3366 WalSndCaughtUp = true;
3367 }
3368 else
3369 {
3370 /* round down to page boundary. */
3371 endptr -= (endptr % XLOG_BLCKSZ);
3372 WalSndCaughtUp = false;
3373 }
3374
3375 nbytes = endptr - startptr;
3376 Assert(nbytes <= MAX_SEND_SIZE);
3377
3378 /*
3379 * OK to read and send the slice.
3380 */
3383
3384 pq_sendint64(&output_message, startptr); /* dataStart */
3385 pq_sendint64(&output_message, SendRqstPtr); /* walEnd */
3386 pq_sendint64(&output_message, 0); /* sendtime, filled in last */
3387
3388 /*
3389 * Read the log directly into the output buffer to avoid extra memcpy
3390 * calls.
3391 */
3393
3394retry:
3395 /* attempt to read WAL from WAL buffers first */
3397 startptr, nbytes, xlogreader->seg.ws_tli);
3398 output_message.len += rbytes;
3399 startptr += rbytes;
3400 nbytes -= rbytes;
3401
3402 /* now read the remaining WAL from WAL file */
3403 if (nbytes > 0 &&
3406 startptr,
3407 nbytes,
3408 xlogreader->seg.ws_tli, /* Pass the current TLI because
3409 * only WalSndSegmentOpen controls
3410 * whether new TLI is needed. */
3411 &errinfo))
3412 WALReadRaiseError(&errinfo);
3413
3414 /* See logical_read_xlog_page(). */
3415 XLByteToSeg(startptr, segno, xlogreader->segcxt.ws_segsize);
3417
3418 /*
3419 * During recovery, the currently-open WAL file might be replaced with the
3420 * file of the same name retrieved from archive. So we always need to
3421 * check what we read was valid after reading into the buffer. If it's
3422 * invalid, we try to open and read the file again.
3423 */
3425 {
3426 WalSnd *walsnd = MyWalSnd;
3427 bool reload;
3428
3429 SpinLockAcquire(&walsnd->mutex);
3430 reload = walsnd->needreload;
3431 walsnd->needreload = false;
3432 SpinLockRelease(&walsnd->mutex);
3433
3434 if (reload && xlogreader->seg.ws_file >= 0)
3435 {
3437
3438 goto retry;
3439 }
3440 }
3441
3442 output_message.len += nbytes;
3444
3445 /*
3446 * Fill the send timestamp last, so that it is taken as late as possible.
3447 */
3450 memcpy(&output_message.data[1 + sizeof(int64) + sizeof(int64)],
3451 tmpbuf.data, sizeof(int64));
3452
3454
3455 sentPtr = endptr;
3456
3457 /* Update shared memory status */
3458 {
3459 WalSnd *walsnd = MyWalSnd;
3460
3461 SpinLockAcquire(&walsnd->mutex);
3462 walsnd->sentPtr = sentPtr;
3463 SpinLockRelease(&walsnd->mutex);
3464 }
3465
3466 /* Report progress of XLOG streaming in PS display */
3468 {
3469 char activitymsg[50];
3470
3471 snprintf(activitymsg, sizeof(activitymsg), "streaming %X/%08X",
3473 set_ps_display(activitymsg);
3474 }
3475}
bool update_process_title
Definition: ps_status.c:31
void enlargeStringInfo(StringInfo str, int needed)
Definition: stringinfo.c:337
TimeLineID ws_tli
Definition: xlogreader.h:49
WALSegmentContext segcxt
Definition: xlogreader.h:271
#define MAX_SEND_SIZE
Definition: walsender.c:114
Size WALReadFromBuffers(char *dstbuf, XLogRecPtr startptr, Size count, TimeLineID tli)
Definition: xlog.c:1751

References am_cascading_walsender, Assert(), CheckXLogRemoved(), StringInfoData::data, DEBUG1, elog, enlargeStringInfo(), GetCurrentTimestamp(), GetFlushRecPtr(), GetStandbyFlushRecPtr(), GetWALInsertionTimeLine(), got_STOPPING, LagTrackerWrite(), StringInfoData::len, list_free_deep(), LSN_FORMAT_ARGS, MAX_SEND_SIZE, WalSnd::mutex, MyWalSnd, WalSnd::needreload, output_message, pq_putmessage_noblock, pq_sendbyte(), pq_sendint64(), PqMsg_CopyData, PqMsg_CopyDone, PqReplMsg_WALData, readTimeLineHistory(), RecoveryInProgress(), resetStringInfo(), XLogReaderState::seg, XLogReaderState::segcxt, sendTimeLine, sendTimeLineIsHistoric, sendTimeLineNextTLI, sendTimeLineValidUpto, sentPtr, WalSnd::sentPtr, set_ps_display(), snprintf, SpinLockAcquire, SpinLockRelease, streamingDoneSending, tliSwitchPoint(), tmpbuf, update_process_title, wal_segment_close(), WALRead(), WALReadFromBuffers(), WALReadRaiseError(), WalSndCaughtUp, WalSndSetState(), WALSNDSTATE_STOPPING, WALOpenSegment::ws_file, WALSegmentContext::ws_segsize, WALOpenSegment::ws_tli, XLByteToSeg, and xlogreader.

Referenced by StartReplication().

Variable Documentation

◆ am_cascading_walsender

◆ am_db_walsender

bool am_db_walsender = false

Definition at line 126 of file walsender.c.

Referenced by check_db(), ClientAuthentication(), InitPostgres(), and ProcessStartupPacket().

◆ am_walsender

◆ got_SIGUSR2

volatile sig_atomic_t got_SIGUSR2 = false
static

◆ got_STOPPING

◆ lag_tracker

LagTracker* lag_tracker
static

Definition at line 238 of file walsender.c.

Referenced by InitWalSender(), LagTrackerRead(), and LagTrackerWrite().

◆ last_processing

TimestampTz last_processing = 0
static

◆ last_reply_timestamp

◆ log_replication_commands

bool log_replication_commands = false

◆ logical_decoding_ctx

LogicalDecodingContext* logical_decoding_ctx = NULL
static

Definition at line 216 of file walsender.c.

Referenced by StartLogicalReplication(), and XLogSendLogical().

◆ max_wal_senders

◆ MyWalSnd

◆ output_message

◆ replication_active

volatile sig_atomic_t replication_active = false
static

◆ reply_message

◆ sendTimeLine

TimeLineID sendTimeLine = 0
static

◆ sendTimeLineIsHistoric

bool sendTimeLineIsHistoric = false
static

◆ sendTimeLineNextTLI

TimeLineID sendTimeLineNextTLI = 0
static

◆ sendTimeLineValidUpto

XLogRecPtr sendTimeLineValidUpto = InvalidXLogRecPtr
static

◆ sentPtr

◆ streamingDoneReceiving

bool streamingDoneReceiving
static

Definition at line 199 of file walsender.c.

Referenced by ProcessRepliesIfAny(), StartReplication(), WalSndLoop(), and WalSndWaitForWal().

◆ streamingDoneSending

bool streamingDoneSending
static

◆ tmpbuf

◆ uploaded_manifest

IncrementalBackupInfo* uploaded_manifest = NULL
static

Definition at line 155 of file walsender.c.

Referenced by exec_replication_command(), and UploadManifest().

◆ uploaded_manifest_mcxt

MemoryContext uploaded_manifest_mcxt = NULL
static

Definition at line 156 of file walsender.c.

Referenced by UploadManifest().

◆ waiting_for_ping_response

bool waiting_for_ping_response = false
static

◆ wake_wal_senders

bool wake_wal_senders = false

Definition at line 138 of file walsender.c.

Referenced by WalSndWakeupProcessRequests().

◆ wal_sender_timeout

int wal_sender_timeout = 60 * 1000

◆ WalSndCaughtUp

bool WalSndCaughtUp = false
static

◆ WalSndCtl

◆ xlogreader