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

PostgreSQL Source Code git master
worker_internal.h File Reference
Include dependency graph for worker_internal.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  LogicalRepWorker
 
struct  ParallelApplyWorkerShared
 
struct  ParallelApplyWorkerInfo
 

Macros

#define isParallelApplyWorker(worker)
 
#define isTablesyncWorker(worker)
 

Typedefs

typedef enum LogicalRepWorkerType LogicalRepWorkerType
 
typedef struct LogicalRepWorker LogicalRepWorker
 
typedef enum ParallelTransState ParallelTransState
 
typedef enum PartialFileSetState PartialFileSetState
 
typedef struct ParallelApplyWorkerShared ParallelApplyWorkerShared
 
typedef struct ParallelApplyWorkerInfo ParallelApplyWorkerInfo
 

Enumerations

enum  LogicalRepWorkerType { WORKERTYPE_UNKNOWN = 0 , WORKERTYPE_TABLESYNC , WORKERTYPE_APPLY , WORKERTYPE_PARALLEL_APPLY }
 
enum  ParallelTransState { PARALLEL_TRANS_UNKNOWN , PARALLEL_TRANS_STARTED , PARALLEL_TRANS_FINISHED }
 
enum  PartialFileSetState { FS_EMPTY , FS_SERIALIZE_IN_PROGRESS , FS_SERIALIZE_DONE , FS_READY }
 

Functions

void logicalrep_worker_attach (int slot)
 
LogicalRepWorkerlogicalrep_worker_find (Oid subid, Oid relid, bool only_running)
 
Listlogicalrep_workers_find (Oid subid, bool only_running, bool acquire_lock)
 
bool logicalrep_worker_launch (LogicalRepWorkerType wtype, Oid dbid, Oid subid, const char *subname, Oid userid, Oid relid, dsm_handle subworker_dsm, bool retain_dead_tuples)
 
void logicalrep_worker_stop (Oid subid, Oid relid)
 
void logicalrep_pa_worker_stop (ParallelApplyWorkerInfo *winfo)
 
void logicalrep_worker_wakeup (Oid subid, Oid relid)
 
void logicalrep_worker_wakeup_ptr (LogicalRepWorker *worker)
 
int logicalrep_sync_worker_count (Oid subid)
 
void ReplicationOriginNameForLogicalRep (Oid suboid, Oid relid, char *originname, Size szoriginname)
 
bool AllTablesyncsReady (void)
 
bool HasSubscriptionRelationsCached (void)
 
void UpdateTwoPhaseState (Oid suboid, char new_state)
 
void process_syncing_tables (XLogRecPtr current_lsn)
 
void invalidate_syncing_table_states (Datum arg, int cacheid, uint32 hashvalue)
 
void stream_start_internal (TransactionId xid, bool first_segment)
 
void stream_stop_internal (TransactionId xid)
 
void apply_spooled_messages (FileSet *stream_fileset, TransactionId xid, XLogRecPtr lsn)
 
void apply_dispatch (StringInfo s)
 
void maybe_reread_subscription (void)
 
void stream_cleanup_files (Oid subid, TransactionId xid)
 
void set_stream_options (WalRcvStreamOptions *options, char *slotname, XLogRecPtr *origin_startpos)
 
void start_apply (XLogRecPtr origin_startpos)
 
void InitializeLogRepWorker (void)
 
void SetupApplyOrSyncWorker (int worker_slot)
 
void DisableSubscriptionAndExit (void)
 
void store_flush_position (XLogRecPtr remote_lsn, XLogRecPtr local_lsn)
 
void apply_error_callback (void *arg)
 
void set_apply_error_context_origin (char *originname)
 
void pa_allocate_worker (TransactionId xid)
 
ParallelApplyWorkerInfopa_find_worker (TransactionId xid)
 
void pa_detach_all_error_mq (void)
 
bool pa_send_data (ParallelApplyWorkerInfo *winfo, Size nbytes, const void *data)
 
void pa_switch_to_partial_serialize (ParallelApplyWorkerInfo *winfo, bool stream_locked)
 
void pa_set_xact_state (ParallelApplyWorkerShared *wshared, ParallelTransState xact_state)
 
void pa_set_stream_apply_worker (ParallelApplyWorkerInfo *winfo)
 
void pa_start_subtrans (TransactionId current_xid, TransactionId top_xid)
 
void pa_reset_subtrans (void)
 
void pa_stream_abort (LogicalRepStreamAbortData *abort_data)
 
void pa_set_fileset_state (ParallelApplyWorkerShared *wshared, PartialFileSetState fileset_state)
 
void pa_lock_stream (TransactionId xid, LOCKMODE lockmode)
 
void pa_unlock_stream (TransactionId xid, LOCKMODE lockmode)
 
void pa_lock_transaction (TransactionId xid, LOCKMODE lockmode)
 
void pa_unlock_transaction (TransactionId xid, LOCKMODE lockmode)
 
void pa_decr_and_wait_stream_block (void)
 
void pa_xact_finish (ParallelApplyWorkerInfo *winfo, XLogRecPtr remote_lsn)
 
static bool am_tablesync_worker (void)
 
static bool am_leader_apply_worker (void)
 
static bool am_parallel_apply_worker (void)
 

Variables

PGDLLIMPORT MemoryContext ApplyContext
 
PGDLLIMPORT MemoryContext ApplyMessageContext
 
PGDLLIMPORT ErrorContextCallbackapply_error_context_stack
 
PGDLLIMPORT ParallelApplyWorkerSharedMyParallelShared
 
PGDLLIMPORT struct WalReceiverConnLogRepWorkerWalRcvConn
 
PGDLLIMPORT SubscriptionMySubscription
 
PGDLLIMPORT LogicalRepWorkerMyLogicalRepWorker
 
PGDLLIMPORT bool in_remote_transaction
 
PGDLLIMPORT bool InitializingApplyWorker
 

Macro Definition Documentation

◆ isParallelApplyWorker

#define isParallelApplyWorker (   worker)
Value:
((worker)->in_use && \
(worker)->type == WORKERTYPE_PARALLEL_APPLY)
@ WORKERTYPE_PARALLEL_APPLY

Definition at line 345 of file worker_internal.h.

◆ isTablesyncWorker

#define isTablesyncWorker (   worker)
Value:
((worker)->in_use && \
(worker)->type == WORKERTYPE_TABLESYNC)
@ WORKERTYPE_TABLESYNC

Definition at line 347 of file worker_internal.h.

Typedef Documentation

◆ LogicalRepWorker

◆ LogicalRepWorkerType

◆ ParallelApplyWorkerInfo

◆ ParallelApplyWorkerShared

◆ ParallelTransState

◆ PartialFileSetState

Enumeration Type Documentation

◆ LogicalRepWorkerType

Enumerator
WORKERTYPE_UNKNOWN 
WORKERTYPE_TABLESYNC 
WORKERTYPE_APPLY 
WORKERTYPE_PARALLEL_APPLY 

Definition at line 29 of file worker_internal.h.

◆ ParallelTransState

Enumerator
PARALLEL_TRANS_UNKNOWN 
PARALLEL_TRANS_STARTED 
PARALLEL_TRANS_FINISHED 

Definition at line 117 of file worker_internal.h.

118{
ParallelTransState
@ PARALLEL_TRANS_UNKNOWN
@ PARALLEL_TRANS_STARTED
@ PARALLEL_TRANS_FINISHED

◆ PartialFileSetState

Enumerator
FS_EMPTY 
FS_SERIALIZE_IN_PROGRESS 
FS_SERIALIZE_DONE 
FS_READY 

Definition at line 140 of file worker_internal.h.

141{
142 FS_EMPTY,
145 FS_READY,
PartialFileSetState
@ FS_EMPTY
@ FS_SERIALIZE_DONE
@ FS_READY
@ FS_SERIALIZE_IN_PROGRESS

Function Documentation

◆ AllTablesyncsReady()

bool AllTablesyncsReady ( void  )

Definition at line 1770 of file tablesync.c.

1771{
1772 bool started_tx = false;
1773 bool has_subrels = false;
1774
1775 /* We need up-to-date sync state info for subscription tables here. */
1776 has_subrels = FetchTableStates(&started_tx);
1777
1778 if (started_tx)
1779 {
1781 pgstat_report_stat(true);
1782 }
1783
1784 /*
1785 * Return false when there are no tables in subscription or not all tables
1786 * are in ready state; true otherwise.
1787 */
1788 return has_subrels && (table_states_not_ready == NIL);
1789}
#define NIL
Definition: pg_list.h:68
long pgstat_report_stat(bool force)
Definition: pgstat.c:692
static List * table_states_not_ready
Definition: tablesync.c:134
static bool FetchTableStates(bool *started_tx)
Definition: tablesync.c:1611
void CommitTransactionCommand(void)
Definition: xact.c:3169

References CommitTransactionCommand(), FetchTableStates(), NIL, pgstat_report_stat(), and table_states_not_ready.

Referenced by pa_can_start(), process_syncing_tables_for_apply(), run_apply_worker(), and wait_for_local_flush().

◆ am_leader_apply_worker()

◆ am_parallel_apply_worker()

◆ am_tablesync_worker()

static bool am_tablesync_worker ( void  )
inlinestatic

◆ apply_dispatch()

void apply_dispatch ( StringInfo  s)

Definition at line 3747 of file worker.c.

3748{
3750 LogicalRepMsgType saved_command;
3751
3752 /*
3753 * Set the current command being applied. Since this function can be
3754 * called recursively when applying spooled changes, save the current
3755 * command.
3756 */
3757 saved_command = apply_error_callback_arg.command;
3759
3760 switch (action)
3761 {
3764 break;
3765
3768 break;
3769
3772 break;
3773
3776 break;
3777
3780 break;
3781
3784 break;
3785
3788 break;
3789
3792 break;
3793
3796 break;
3797
3799
3800 /*
3801 * Logical replication does not use generic logical messages yet.
3802 * Although, it could be used by other applications that use this
3803 * output plugin.
3804 */
3805 break;
3806
3809 break;
3810
3813 break;
3814
3817 break;
3818
3821 break;
3822
3825 break;
3826
3829 break;
3830
3833 break;
3834
3837 break;
3838
3841 break;
3842
3843 default:
3844 ereport(ERROR,
3845 (errcode(ERRCODE_PROTOCOL_VIOLATION),
3846 errmsg("invalid logical replication message type \"??? (%d)\"", action)));
3847 }
3848
3849 /* Reset the current command */
3850 apply_error_callback_arg.command = saved_command;
3851}
static void apply_handle_stream_prepare(StringInfo s)
Definition: worker.c:1500
static void apply_handle_type(StringInfo s)
Definition: worker.c:2561
static void apply_handle_truncate(StringInfo s)
Definition: worker.c:3619
static void apply_handle_update(StringInfo s)
Definition: worker.c:2765
static void apply_handle_stream_commit(StringInfo s)
Definition: worker.c:2368
static void apply_handle_commit_prepared(StringInfo s)
Definition: worker.c:1393
static ApplyErrorCallbackArg apply_error_callback_arg
Definition: worker.c:459
static void apply_handle_delete(StringInfo s)
Definition: worker.c:2987
static void apply_handle_begin(StringInfo s)
Definition: worker.c:1205
static void apply_handle_commit(StringInfo s)
Definition: worker.c:1230
static void apply_handle_stream_abort(StringInfo s)
Definition: worker.c:2049
static void apply_handle_relation(StringInfo s)
Definition: worker.c:2538
static void apply_handle_prepare(StringInfo s)
Definition: worker.c:1322
static void apply_handle_rollback_prepared(StringInfo s)
Definition: worker.c:1442
static void apply_handle_stream_stop(StringInfo s)
Definition: worker.c:1863
static void apply_handle_origin(StringInfo s)
Definition: worker.c:1645
static void apply_handle_begin_prepare(StringInfo s)
Definition: worker.c:1256
static void apply_handle_stream_start(StringInfo s)
Definition: worker.c:1704
static void apply_handle_insert(StringInfo s)
Definition: worker.c:2608
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
LogicalRepMsgType
Definition: logicalproto.h:58
@ LOGICAL_REP_MSG_INSERT
Definition: logicalproto.h:62
@ LOGICAL_REP_MSG_TRUNCATE
Definition: logicalproto.h:65
@ LOGICAL_REP_MSG_STREAM_STOP
Definition: logicalproto.h:74
@ LOGICAL_REP_MSG_BEGIN
Definition: logicalproto.h:59
@ LOGICAL_REP_MSG_STREAM_PREPARE
Definition: logicalproto.h:77
@ LOGICAL_REP_MSG_STREAM_ABORT
Definition: logicalproto.h:76
@ LOGICAL_REP_MSG_BEGIN_PREPARE
Definition: logicalproto.h:69
@ LOGICAL_REP_MSG_STREAM_START
Definition: logicalproto.h:73
@ LOGICAL_REP_MSG_COMMIT
Definition: logicalproto.h:60
@ LOGICAL_REP_MSG_PREPARE
Definition: logicalproto.h:70
@ LOGICAL_REP_MSG_RELATION
Definition: logicalproto.h:66
@ LOGICAL_REP_MSG_MESSAGE
Definition: logicalproto.h:68
@ LOGICAL_REP_MSG_ROLLBACK_PREPARED
Definition: logicalproto.h:72
@ LOGICAL_REP_MSG_COMMIT_PREPARED
Definition: logicalproto.h:71
@ LOGICAL_REP_MSG_TYPE
Definition: logicalproto.h:67
@ LOGICAL_REP_MSG_DELETE
Definition: logicalproto.h:64
@ LOGICAL_REP_MSG_STREAM_COMMIT
Definition: logicalproto.h:75
@ LOGICAL_REP_MSG_ORIGIN
Definition: logicalproto.h:61
@ LOGICAL_REP_MSG_UPDATE
Definition: logicalproto.h:63
int pq_getmsgbyte(StringInfo msg)
Definition: pqformat.c:399
LogicalRepMsgType command
Definition: worker.c:325

References generate_unaccent_rules::action, apply_error_callback_arg, apply_handle_begin(), apply_handle_begin_prepare(), apply_handle_commit(), apply_handle_commit_prepared(), apply_handle_delete(), apply_handle_insert(), apply_handle_origin(), apply_handle_prepare(), apply_handle_relation(), apply_handle_rollback_prepared(), apply_handle_stream_abort(), apply_handle_stream_commit(), apply_handle_stream_prepare(), apply_handle_stream_start(), apply_handle_stream_stop(), apply_handle_truncate(), apply_handle_type(), apply_handle_update(), ApplyErrorCallbackArg::command, ereport, errcode(), errmsg(), ERROR, LOGICAL_REP_MSG_BEGIN, LOGICAL_REP_MSG_BEGIN_PREPARE, LOGICAL_REP_MSG_COMMIT, LOGICAL_REP_MSG_COMMIT_PREPARED, LOGICAL_REP_MSG_DELETE, LOGICAL_REP_MSG_INSERT, LOGICAL_REP_MSG_MESSAGE, LOGICAL_REP_MSG_ORIGIN, LOGICAL_REP_MSG_PREPARE, LOGICAL_REP_MSG_RELATION, LOGICAL_REP_MSG_ROLLBACK_PREPARED, LOGICAL_REP_MSG_STREAM_ABORT, LOGICAL_REP_MSG_STREAM_COMMIT, LOGICAL_REP_MSG_STREAM_PREPARE, LOGICAL_REP_MSG_STREAM_START, LOGICAL_REP_MSG_STREAM_STOP, LOGICAL_REP_MSG_TRUNCATE, LOGICAL_REP_MSG_TYPE, LOGICAL_REP_MSG_UPDATE, and pq_getmsgbyte().

Referenced by apply_spooled_messages(), LogicalParallelApplyLoop(), and LogicalRepApplyLoop().

◆ apply_error_callback()

void apply_error_callback ( void *  arg)

Definition at line 6118 of file worker.c.

6119{
6121
6123 return;
6124
6125 Assert(errarg->origin_name);
6126
6127 if (errarg->rel == NULL)
6128 {
6129 if (!TransactionIdIsValid(errarg->remote_xid))
6130 errcontext("processing remote data for replication origin \"%s\" during message type \"%s\"",
6131 errarg->origin_name,
6133 else if (XLogRecPtrIsInvalid(errarg->finish_lsn))
6134 errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" in transaction %u",
6135 errarg->origin_name,
6137 errarg->remote_xid);
6138 else
6139 errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" in transaction %u, finished at %X/%08X",
6140 errarg->origin_name,
6142 errarg->remote_xid,
6143 LSN_FORMAT_ARGS(errarg->finish_lsn));
6144 }
6145 else
6146 {
6147 if (errarg->remote_attnum < 0)
6148 {
6149 if (XLogRecPtrIsInvalid(errarg->finish_lsn))
6150 errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" in transaction %u",
6151 errarg->origin_name,
6153 errarg->rel->remoterel.nspname,
6154 errarg->rel->remoterel.relname,
6155 errarg->remote_xid);
6156 else
6157 errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" in transaction %u, finished at %X/%08X",
6158 errarg->origin_name,
6160 errarg->rel->remoterel.nspname,
6161 errarg->rel->remoterel.relname,
6162 errarg->remote_xid,
6163 LSN_FORMAT_ARGS(errarg->finish_lsn));
6164 }
6165 else
6166 {
6167 if (XLogRecPtrIsInvalid(errarg->finish_lsn))
6168 errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" column \"%s\" in transaction %u",
6169 errarg->origin_name,
6171 errarg->rel->remoterel.nspname,
6172 errarg->rel->remoterel.relname,
6173 errarg->rel->remoterel.attnames[errarg->remote_attnum],
6174 errarg->remote_xid);
6175 else
6176 errcontext("processing remote data for replication origin \"%s\" during message type \"%s\" for replication target relation \"%s.%s\" column \"%s\" in transaction %u, finished at %X/%08X",
6177 errarg->origin_name,
6179 errarg->rel->remoterel.nspname,
6180 errarg->rel->remoterel.relname,
6181 errarg->rel->remoterel.attnames[errarg->remote_attnum],
6182 errarg->remote_xid,
6183 LSN_FORMAT_ARGS(errarg->finish_lsn));
6184 }
6185 }
6186}
#define errcontext
Definition: elog.h:198
const char * logicalrep_message_type(LogicalRepMsgType action)
Definition: proto.c:1209
TransactionId remote_xid
Definition: worker.c:330
XLogRecPtr finish_lsn
Definition: worker.c:331
LogicalRepRelMapEntry * rel
Definition: worker.c:326
LogicalRepRelation remoterel
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:46
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29

References apply_error_callback_arg, Assert(), LogicalRepRelation::attnames, ApplyErrorCallbackArg::command, errcontext, ApplyErrorCallbackArg::finish_lsn, logicalrep_message_type(), LSN_FORMAT_ARGS, LogicalRepRelation::nspname, ApplyErrorCallbackArg::origin_name, ApplyErrorCallbackArg::rel, LogicalRepRelation::relname, ApplyErrorCallbackArg::remote_attnum, ApplyErrorCallbackArg::remote_xid, LogicalRepRelMapEntry::remoterel, TransactionIdIsValid, and XLogRecPtrIsInvalid.

Referenced by LogicalParallelApplyLoop(), and LogicalRepApplyLoop().

◆ apply_spooled_messages()

void apply_spooled_messages ( FileSet stream_fileset,
TransactionId  xid,
XLogRecPtr  lsn 
)

Definition at line 2238 of file worker.c.

2240{
2241 int nchanges;
2242 char path[MAXPGPATH];
2243 char *buffer = NULL;
2244 MemoryContext oldcxt;
2245 ResourceOwner oldowner;
2246 int fileno;
2247 off_t offset;
2248
2251
2252 /* Make sure we have an open transaction */
2254
2255 /*
2256 * Allocate file handle and memory required to process all the messages in
2257 * TopTransactionContext to avoid them getting reset after each message is
2258 * processed.
2259 */
2261
2262 /* Open the spool file for the committed/prepared transaction */
2264 elog(DEBUG1, "replaying changes from file \"%s\"", path);
2265
2266 /*
2267 * Make sure the file is owned by the toplevel transaction so that the
2268 * file will not be accidentally closed when aborting a subtransaction.
2269 */
2270 oldowner = CurrentResourceOwner;
2272
2273 stream_fd = BufFileOpenFileSet(stream_fileset, path, O_RDONLY, false);
2274
2275 CurrentResourceOwner = oldowner;
2276
2277 buffer = palloc(BLCKSZ);
2278
2279 MemoryContextSwitchTo(oldcxt);
2280
2281 remote_final_lsn = lsn;
2282
2283 /*
2284 * Make sure the handle apply_dispatch methods are aware we're in a remote
2285 * transaction.
2286 */
2287 in_remote_transaction = true;
2289
2291
2292 /*
2293 * Read the entries one by one and pass them through the same logic as in
2294 * apply_dispatch.
2295 */
2296 nchanges = 0;
2297 while (true)
2298 {
2300 size_t nbytes;
2301 int len;
2302
2304
2305 /* read length of the on-disk record */
2306 nbytes = BufFileReadMaybeEOF(stream_fd, &len, sizeof(len), true);
2307
2308 /* have we reached end of the file? */
2309 if (nbytes == 0)
2310 break;
2311
2312 /* do we have a correct length? */
2313 if (len <= 0)
2314 elog(ERROR, "incorrect length %d in streaming transaction's changes file \"%s\"",
2315 len, path);
2316
2317 /* make sure we have sufficiently large buffer */
2318 buffer = repalloc(buffer, len);
2319
2320 /* and finally read the data into the buffer */
2321 BufFileReadExact(stream_fd, buffer, len);
2322
2323 BufFileTell(stream_fd, &fileno, &offset);
2324
2325 /* init a stringinfo using the buffer and call apply_dispatch */
2326 initReadOnlyStringInfo(&s2, buffer, len);
2327
2328 /* Ensure we are reading the data into our memory context. */
2330
2332
2334
2335 MemoryContextSwitchTo(oldcxt);
2336
2337 nchanges++;
2338
2339 /*
2340 * It is possible the file has been closed because we have processed
2341 * the transaction end message like stream_commit in which case that
2342 * must be the last message.
2343 */
2344 if (!stream_fd)
2345 {
2346 ensure_last_message(stream_fileset, xid, fileno, offset);
2347 break;
2348 }
2349
2350 if (nchanges % 1000 == 0)
2351 elog(DEBUG1, "replayed %d changes from file \"%s\"",
2352 nchanges, path);
2353 }
2354
2355 if (stream_fd)
2357
2358 elog(DEBUG1, "replayed %d (all) changes from file \"%s\"",
2359 nchanges, path);
2360
2361 return;
2362}
static void begin_replication_step(void)
Definition: worker.c:721
static void end_replication_step(void)
Definition: worker.c:744
MemoryContext ApplyMessageContext
Definition: worker.c:471
static void changes_filename(char *path, Oid subid, TransactionId xid)
Definition: worker.c:5336
static BufFile * stream_fd
Definition: worker.c:520
bool in_remote_transaction
Definition: worker.c:484
void apply_dispatch(StringInfo s)
Definition: worker.c:3747
static void ensure_last_message(FileSet *stream_fileset, TransactionId xid, int fileno, off_t offset)
Definition: worker.c:2206
static XLogRecPtr remote_final_lsn
Definition: worker.c:485
static void maybe_start_skipping_changes(XLogRecPtr finish_lsn)
Definition: worker.c:5980
static void stream_close_file(void)
Definition: worker.c:5419
void pgstat_report_activity(BackendState state, const char *cmd_str)
@ STATE_RUNNING
BufFile * BufFileOpenFileSet(FileSet *fileset, const char *name, int mode, bool missing_ok)
Definition: buffile.c:291
void BufFileReadExact(BufFile *file, void *ptr, size_t size)
Definition: buffile.c:654
void BufFileTell(BufFile *file, int *fileno, off_t *offset)
Definition: buffile.c:833
size_t BufFileReadMaybeEOF(BufFile *file, void *ptr, size_t size, bool eofOK)
Definition: buffile.c:664
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:226
LogicalRepWorker * MyLogicalRepWorker
Definition: launcher.c:56
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:400
MemoryContext TopTransactionContext
Definition: mcxt.c:171
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1610
void * palloc(Size size)
Definition: mcxt.c:1365
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define MAXPGPATH
const void size_t len
char * s2
ResourceOwner TopTransactionResourceOwner
Definition: resowner.c:175
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173
static void initReadOnlyStringInfo(StringInfo str, char *data, int len)
Definition: stringinfo.h:157
static bool am_parallel_apply_worker(void)

References am_parallel_apply_worker(), apply_dispatch(), ApplyMessageContext, begin_replication_step(), BufFileOpenFileSet(), BufFileReadExact(), BufFileReadMaybeEOF(), BufFileTell(), changes_filename(), CHECK_FOR_INTERRUPTS, CurrentResourceOwner, DEBUG1, elog, end_replication_step(), ensure_last_message(), ERROR, in_remote_transaction, initReadOnlyStringInfo(), len, MAXPGPATH, maybe_start_skipping_changes(), MemoryContextReset(), MemoryContextSwitchTo(), MyLogicalRepWorker, palloc(), pgstat_report_activity(), remote_final_lsn, repalloc(), s2, STATE_RUNNING, stream_close_file(), stream_fd, LogicalRepWorker::subid, TopTransactionContext, and TopTransactionResourceOwner.

Referenced by apply_handle_stream_commit(), apply_handle_stream_prepare(), and pa_process_spooled_messages_if_required().

◆ DisableSubscriptionAndExit()

void DisableSubscriptionAndExit ( void  )

Definition at line 5905 of file worker.c.

5906{
5907 /*
5908 * Emit the error message, and recover from the error state to an idle
5909 * state
5910 */
5912
5916
5918
5919 /* Report the worker failed during either table synchronization or apply */
5922
5923 /* Disable the subscription */
5925
5926 /*
5927 * Updating pg_subscription might involve TOAST table access, so ensure we
5928 * have a valid snapshot.
5929 */
5931
5935
5936 /* Ensure we remove no-longer-useful entry for worker's start time */
5939
5940 /* Notify the subscription has been disabled and exit */
5941 ereport(LOG,
5942 errmsg("subscription \"%s\" has been disabled because of an error",
5944
5945 /*
5946 * Skip the track_commit_timestamp check when disabling the worker due to
5947 * an error, as verifying commit timestamps is unnecessary in this
5948 * context.
5949 */
5953
5954 proc_exit(0);
5955}
Subscription * MySubscription
Definition: worker.c:479
void EmitErrorReport(void)
Definition: elog.c:1695
void FlushErrorState(void)
Definition: elog.c:1875
#define LOG
Definition: elog.h:31
#define WARNING
Definition: elog.h:36
void proc_exit(int code)
Definition: ipc.c:104
void ApplyLauncherForgetWorkerStartTime(Oid subid)
Definition: launcher.c:1101
#define RESUME_INTERRUPTS()
Definition: miscadmin.h:135
#define HOLD_INTERRUPTS()
Definition: miscadmin.h:133
void DisableSubscription(Oid subid)
void pgstat_report_subscription_error(Oid subid, bool is_apply_error)
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:271
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:680
void PopActiveSnapshot(void)
Definition: snapmgr.c:773
void CheckSubDeadTupleRetention(bool check_guc, bool sub_disabled, int elevel_for_sub_disabled, bool retain_dead_tuples, bool retention_active, bool max_retention_set)
static bool am_tablesync_worker(void)
static bool am_leader_apply_worker(void)
void StartTransactionCommand(void)
Definition: xact.c:3071
void AbortOutOfAnyTransaction(void)
Definition: xact.c:4874

References AbortOutOfAnyTransaction(), am_leader_apply_worker(), am_tablesync_worker(), ApplyLauncherForgetWorkerStartTime(), CheckSubDeadTupleRetention(), CommitTransactionCommand(), DisableSubscription(), EmitErrorReport(), ereport, errmsg(), FlushErrorState(), GetTransactionSnapshot(), HOLD_INTERRUPTS, LOG, MyLogicalRepWorker, MySubscription, Subscription::name, Subscription::oid, pgstat_report_subscription_error(), PopActiveSnapshot(), proc_exit(), PushActiveSnapshot(), RESUME_INTERRUPTS, Subscription::retaindeadtuples, Subscription::retentionactive, StartTransactionCommand(), LogicalRepWorker::subid, and WARNING.

Referenced by start_apply(), and start_table_sync().

◆ HasSubscriptionRelationsCached()

bool HasSubscriptionRelationsCached ( void  )

Definition at line 1800 of file tablesync.c.

1801{
1802 bool started_tx;
1803 bool has_subrels;
1804
1805 /* We need up-to-date subscription tables info here */
1806 has_subrels = FetchTableStates(&started_tx);
1807
1808 if (started_tx)
1809 {
1811 pgstat_report_stat(true);
1812 }
1813
1814 return has_subrels;
1815}

References CommitTransactionCommand(), FetchTableStates(), and pgstat_report_stat().

Referenced by wait_for_local_flush().

◆ InitializeLogRepWorker()

void InitializeLogRepWorker ( void  )

Definition at line 5705 of file worker.c.

5706{
5707 MemoryContext oldctx;
5708
5709 /* Run as replica session replication role. */
5710 SetConfigOption("session_replication_role", "replica",
5712
5713 /* Connect to our database. */
5716 0);
5717
5718 /*
5719 * Set always-secure search path, so malicious users can't redirect user
5720 * code (e.g. pg_index.indexprs).
5721 */
5722 SetConfigOption("search_path", "", PGC_SUSET, PGC_S_OVERRIDE);
5723
5724 /* Load the subscription into persistent memory context. */
5726 "ApplyContext",
5730
5731 /*
5732 * Lock the subscription to prevent it from being concurrently dropped,
5733 * then re-verify its existence. After the initialization, the worker will
5734 * be terminated gracefully if the subscription is dropped.
5735 */
5736 LockSharedObject(SubscriptionRelationId, MyLogicalRepWorker->subid, 0,
5739 if (!MySubscription)
5740 {
5741 ereport(LOG,
5742 (errmsg("logical replication worker for subscription %u will not start because the subscription was removed during startup",
5744
5745 /* Ensure we remove no-longer-useful entry for worker's start time */
5748
5749 proc_exit(0);
5750 }
5751
5752 MySubscriptionValid = true;
5753 MemoryContextSwitchTo(oldctx);
5754
5755 if (!MySubscription->enabled)
5756 {
5757 ereport(LOG,
5758 (errmsg("logical replication worker for subscription \"%s\" will not start because the subscription was disabled during startup",
5759 MySubscription->name)));
5760
5762 }
5763
5764 /*
5765 * Restart the worker if retain_dead_tuples was enabled during startup.
5766 *
5767 * At this point, the replication slot used for conflict detection might
5768 * not exist yet, or could be dropped soon if the launcher perceives
5769 * retain_dead_tuples as disabled. To avoid unnecessary tracking of
5770 * oldest_nonremovable_xid when the slot is absent or at risk of being
5771 * dropped, a restart is initiated.
5772 *
5773 * The oldest_nonremovable_xid should be initialized only when the
5774 * subscription's retention is active before launching the worker. See
5775 * logicalrep_worker_launch.
5776 */
5777 if (am_leader_apply_worker() &&
5781 {
5782 ereport(LOG,
5783 errmsg("logical replication worker for subscription \"%s\" will restart because the option %s was enabled during startup",
5784 MySubscription->name, "retain_dead_tuples"));
5785
5787 }
5788
5789 /* Setup synchronous commit according to the user's wishes */
5790 SetConfigOption("synchronous_commit", MySubscription->synccommit,
5792
5793 /*
5794 * Keep us informed about subscription or role changes. Note that the
5795 * role's superuser privilege can be revoked.
5796 */
5797 CacheRegisterSyscacheCallback(SUBSCRIPTIONOID,
5799 (Datum) 0);
5800
5803 (Datum) 0);
5804
5805 if (am_tablesync_worker())
5806 ereport(LOG,
5807 (errmsg("logical replication table synchronization worker for subscription \"%s\", table \"%s\" has started",
5810 else
5811 ereport(LOG,
5812 (errmsg("logical replication apply worker for subscription \"%s\" has started",
5813 MySubscription->name)));
5814
5816}
static void subscription_change_cb(Datum arg, int cacheid, uint32 hashvalue)
Definition: worker.c:5136
static void apply_worker_exit(void)
Definition: worker.c:4973
MemoryContext ApplyContext
Definition: worker.c:472
static bool MySubscriptionValid
Definition: worker.c:480
void BackgroundWorkerInitializeConnectionByOid(Oid dboid, Oid useroid, uint32 flags)
Definition: bgworker.c:887
void SetConfigOption(const char *name, const char *value, GucContext context, GucSource source)
Definition: guc.c:4337
@ PGC_S_OVERRIDE
Definition: guc.h:123
@ PGC_SUSET
Definition: guc.h:78
@ PGC_BACKEND
Definition: guc.h:77
void CacheRegisterSyscacheCallback(int cacheid, SyscacheCallbackFunction func, Datum arg)
Definition: inval.c:1812
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
Definition: lmgr.c:1088
#define AccessShareLock
Definition: lockdefs.h:36
char * get_rel_name(Oid relid)
Definition: lsyscache.c:2095
MemoryContext TopMemoryContext
Definition: mcxt.c:166
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
Subscription * GetSubscription(Oid subid, bool missing_ok)
uint64_t Datum
Definition: postgres.h:70
TransactionId oldest_nonremovable_xid

References AccessShareLock, ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, am_leader_apply_worker(), am_tablesync_worker(), apply_worker_exit(), ApplyContext, ApplyLauncherForgetWorkerStartTime(), BackgroundWorkerInitializeConnectionByOid(), CacheRegisterSyscacheCallback(), CommitTransactionCommand(), LogicalRepWorker::dbid, Subscription::enabled, ereport, errmsg(), get_rel_name(), GetSubscription(), LockSharedObject(), LOG, MemoryContextSwitchTo(), MyLogicalRepWorker, MySubscription, MySubscriptionValid, Subscription::name, LogicalRepWorker::oldest_nonremovable_xid, PGC_BACKEND, PGC_S_OVERRIDE, PGC_SUSET, proc_exit(), LogicalRepWorker::relid, Subscription::retaindeadtuples, Subscription::retentionactive, SetConfigOption(), StartTransactionCommand(), LogicalRepWorker::subid, subscription_change_cb(), Subscription::synccommit, TopMemoryContext, TransactionIdIsValid, and LogicalRepWorker::userid.

Referenced by ParallelApplyWorkerMain(), and SetupApplyOrSyncWorker().

◆ invalidate_syncing_table_states()

void invalidate_syncing_table_states ( Datum  arg,
int  cacheid,
uint32  hashvalue 
)

Definition at line 280 of file tablesync.c.

281{
283}
@ SYNC_TABLE_STATE_NEEDS_REBUILD
Definition: tablesync.c:128
static SyncingTablesState table_states_validity
Definition: tablesync.c:133

References SYNC_TABLE_STATE_NEEDS_REBUILD, and table_states_validity.

Referenced by ParallelApplyWorkerMain(), and SetupApplyOrSyncWorker().

◆ logicalrep_pa_worker_stop()

void logicalrep_pa_worker_stop ( ParallelApplyWorkerInfo winfo)

Definition at line 657 of file launcher.c.

658{
659 int slot_no;
660 uint16 generation;
661 LogicalRepWorker *worker;
662
663 SpinLockAcquire(&winfo->shared->mutex);
664 generation = winfo->shared->logicalrep_worker_generation;
665 slot_no = winfo->shared->logicalrep_worker_slot_no;
666 SpinLockRelease(&winfo->shared->mutex);
667
668 Assert(slot_no >= 0 && slot_no < max_logical_replication_workers);
669
670 /*
671 * Detach from the error_mq_handle for the parallel apply worker before
672 * stopping it. This prevents the leader apply worker from trying to
673 * receive the message from the error queue that might already be detached
674 * by the parallel apply worker.
675 */
676 if (winfo->error_mq_handle)
677 {
679 winfo->error_mq_handle = NULL;
680 }
681
682 LWLockAcquire(LogicalRepWorkerLock, LW_SHARED);
683
684 worker = &LogicalRepCtx->workers[slot_no];
686
687 /*
688 * Only stop the worker if the generation matches and the worker is alive.
689 */
690 if (worker->generation == generation && worker->proc)
692
693 LWLockRelease(LogicalRepWorkerLock);
694}
uint16_t uint16
Definition: c.h:538
int max_logical_replication_workers
Definition: launcher.c:52
static void logicalrep_worker_stop_internal(LogicalRepWorker *worker, int signo)
Definition: launcher.c:551
static LogicalRepCtxStruct * LogicalRepCtx
Definition: launcher.c:71
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_SHARED
Definition: lwlock.h:113
void shm_mq_detach(shm_mq_handle *mqh)
Definition: shm_mq.c:843
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
LogicalRepWorker workers[FLEXIBLE_ARRAY_MEMBER]
Definition: launcher.c:68
shm_mq_handle * error_mq_handle
ParallelApplyWorkerShared * shared
#define SIGUSR2
Definition: win32_port.h:171

References Assert(), ParallelApplyWorkerInfo::error_mq_handle, LogicalRepWorker::generation, isParallelApplyWorker, ParallelApplyWorkerShared::logicalrep_worker_generation, ParallelApplyWorkerShared::logicalrep_worker_slot_no, logicalrep_worker_stop_internal(), LogicalRepCtx, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_logical_replication_workers, ParallelApplyWorkerShared::mutex, LogicalRepWorker::proc, ParallelApplyWorkerInfo::shared, shm_mq_detach(), SIGUSR2, SpinLockAcquire, SpinLockRelease, and LogicalRepCtxStruct::workers.

Referenced by pa_free_worker().

◆ logicalrep_sync_worker_count()

int logicalrep_sync_worker_count ( Oid  subid)

Definition at line 874 of file launcher.c.

875{
876 int i;
877 int res = 0;
878
879 Assert(LWLockHeldByMe(LogicalRepWorkerLock));
880
881 /* Search for attached worker for a given subscription id. */
882 for (i = 0; i < max_logical_replication_workers; i++)
883 {
885
886 if (isTablesyncWorker(w) && w->subid == subid)
887 res++;
888 }
889
890 return res;
891}
int i
Definition: isn.c:77
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1977

References Assert(), i, isTablesyncWorker, LogicalRepCtx, LWLockHeldByMe(), max_logical_replication_workers, LogicalRepWorker::subid, and LogicalRepCtxStruct::workers.

Referenced by logicalrep_worker_launch(), and process_syncing_tables_for_apply().

◆ logicalrep_worker_attach()

void logicalrep_worker_attach ( int  slot)

Definition at line 731 of file launcher.c.

732{
733 /* Block concurrent access. */
734 LWLockAcquire(LogicalRepWorkerLock, LW_EXCLUSIVE);
735
736 Assert(slot >= 0 && slot < max_logical_replication_workers);
738
740 {
741 LWLockRelease(LogicalRepWorkerLock);
743 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
744 errmsg("logical replication worker slot %d is empty, cannot attach",
745 slot)));
746 }
747
749 {
750 LWLockRelease(LogicalRepWorkerLock);
752 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
753 errmsg("logical replication worker slot %d is already used by "
754 "another worker, cannot attach", slot)));
755 }
756
759
760 LWLockRelease(LogicalRepWorkerLock);
761}
void before_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:337
static void logicalrep_worker_onexit(int code, Datum arg)
Definition: launcher.c:844
@ LW_EXCLUSIVE
Definition: lwlock.h:112
PGPROC * MyProc
Definition: proc.c:66

References Assert(), before_shmem_exit(), ereport, errcode(), errmsg(), ERROR, LogicalRepWorker::in_use, logicalrep_worker_onexit(), LogicalRepCtx, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), max_logical_replication_workers, MyLogicalRepWorker, MyProc, LogicalRepWorker::proc, and LogicalRepCtxStruct::workers.

Referenced by ParallelApplyWorkerMain(), and SetupApplyOrSyncWorker().

◆ logicalrep_worker_find()

LogicalRepWorker * logicalrep_worker_find ( Oid  subid,
Oid  relid,
bool  only_running 
)

Definition at line 254 of file launcher.c.

255{
256 int i;
257 LogicalRepWorker *res = NULL;
258
259 Assert(LWLockHeldByMe(LogicalRepWorkerLock));
260
261 /* Search for attached worker for a given subscription id. */
262 for (i = 0; i < max_logical_replication_workers; i++)
263 {
265
266 /* Skip parallel apply workers. */
268 continue;
269
270 if (w->in_use && w->subid == subid && w->relid == relid &&
271 (!only_running || w->proc))
272 {
273 res = w;
274 break;
275 }
276 }
277
278 return res;
279}

References Assert(), i, LogicalRepWorker::in_use, isParallelApplyWorker, LogicalRepCtx, LWLockHeldByMe(), max_logical_replication_workers, LogicalRepWorker::proc, LogicalRepWorker::relid, LogicalRepWorker::subid, and LogicalRepCtxStruct::workers.

Referenced by ApplyLauncherMain(), FindDeletedTupleInLocalRel(), logicalrep_worker_stop(), logicalrep_worker_wakeup(), process_syncing_tables_for_apply(), wait_for_relation_state_change(), and wait_for_worker_state_change().

◆ logicalrep_worker_launch()

bool logicalrep_worker_launch ( LogicalRepWorkerType  wtype,
Oid  dbid,
Oid  subid,
const char *  subname,
Oid  userid,
Oid  relid,
dsm_handle  subworker_dsm,
bool  retain_dead_tuples 
)

Definition at line 317 of file launcher.c.

321{
323 BackgroundWorkerHandle *bgw_handle;
324 uint16 generation;
325 int i;
326 int slot = 0;
327 LogicalRepWorker *worker = NULL;
328 int nsyncworkers;
329 int nparallelapplyworkers;
331 bool is_tablesync_worker = (wtype == WORKERTYPE_TABLESYNC);
332 bool is_parallel_apply_worker = (wtype == WORKERTYPE_PARALLEL_APPLY);
333
334 /*----------
335 * Sanity checks:
336 * - must be valid worker type
337 * - tablesync workers are only ones to have relid
338 * - parallel apply worker is the only kind of subworker
339 * - The replication slot used in conflict detection is created when
340 * retain_dead_tuples is enabled
341 */
342 Assert(wtype != WORKERTYPE_UNKNOWN);
343 Assert(is_tablesync_worker == OidIsValid(relid));
344 Assert(is_parallel_apply_worker == (subworker_dsm != DSM_HANDLE_INVALID));
345 Assert(!retain_dead_tuples || MyReplicationSlot);
346
348 (errmsg_internal("starting logical replication worker for subscription \"%s\"",
349 subname)));
350
351 /* Report this after the initial starting message for consistency. */
354 (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
355 errmsg("cannot start logical replication workers when \"max_active_replication_origins\" is 0")));
356
357 /*
358 * We need to do the modification of the shared memory under lock so that
359 * we have consistent view.
360 */
361 LWLockAcquire(LogicalRepWorkerLock, LW_EXCLUSIVE);
362
363retry:
364 /* Find unused worker slot. */
365 for (i = 0; i < max_logical_replication_workers; i++)
366 {
368
369 if (!w->in_use)
370 {
371 worker = w;
372 slot = i;
373 break;
374 }
375 }
376
377 nsyncworkers = logicalrep_sync_worker_count(subid);
378
380
381 /*
382 * If we didn't find a free slot, try to do garbage collection. The
383 * reason we do this is because if some worker failed to start up and its
384 * parent has crashed while waiting, the in_use state was never cleared.
385 */
386 if (worker == NULL || nsyncworkers >= max_sync_workers_per_subscription)
387 {
388 bool did_cleanup = false;
389
390 for (i = 0; i < max_logical_replication_workers; i++)
391 {
393
394 /*
395 * If the worker was marked in use but didn't manage to attach in
396 * time, clean it up.
397 */
398 if (w->in_use && !w->proc &&
401 {
403 "logical replication worker for subscription %u took too long to start; canceled",
404 w->subid);
405
407 did_cleanup = true;
408 }
409 }
410
411 if (did_cleanup)
412 goto retry;
413 }
414
415 /*
416 * We don't allow to invoke more sync workers once we have reached the
417 * sync worker limit per subscription. So, just return silently as we
418 * might get here because of an otherwise harmless race condition.
419 */
420 if (is_tablesync_worker && nsyncworkers >= max_sync_workers_per_subscription)
421 {
422 LWLockRelease(LogicalRepWorkerLock);
423 return false;
424 }
425
426 nparallelapplyworkers = logicalrep_pa_worker_count(subid);
427
428 /*
429 * Return false if the number of parallel apply workers reached the limit
430 * per subscription.
431 */
432 if (is_parallel_apply_worker &&
433 nparallelapplyworkers >= max_parallel_apply_workers_per_subscription)
434 {
435 LWLockRelease(LogicalRepWorkerLock);
436 return false;
437 }
438
439 /*
440 * However if there are no more free worker slots, inform user about it
441 * before exiting.
442 */
443 if (worker == NULL)
444 {
445 LWLockRelease(LogicalRepWorkerLock);
447 (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
448 errmsg("out of logical replication worker slots"),
449 errhint("You might need to increase \"%s\".", "max_logical_replication_workers")));
450 return false;
451 }
452
453 /* Prepare the worker slot. */
454 worker->type = wtype;
455 worker->launch_time = now;
456 worker->in_use = true;
457 worker->generation++;
458 worker->proc = NULL;
459 worker->dbid = dbid;
460 worker->userid = userid;
461 worker->subid = subid;
462 worker->relid = relid;
463 worker->relstate = SUBREL_STATE_UNKNOWN;
465 worker->stream_fileset = NULL;
466 worker->leader_pid = is_parallel_apply_worker ? MyProcPid : InvalidPid;
467 worker->parallel_apply = is_parallel_apply_worker;
468 worker->oldest_nonremovable_xid = retain_dead_tuples
471 worker->last_lsn = InvalidXLogRecPtr;
476
477 /* Before releasing lock, remember generation for future identification. */
478 generation = worker->generation;
479
480 LWLockRelease(LogicalRepWorkerLock);
481
482 /* Register the new dynamic worker. */
483 memset(&bgw, 0, sizeof(bgw));
487 snprintf(bgw.bgw_library_name, MAXPGPATH, "postgres");
488
489 switch (worker->type)
490 {
491 case WORKERTYPE_APPLY:
492 snprintf(bgw.bgw_function_name, BGW_MAXLEN, "ApplyWorkerMain");
494 "logical replication apply worker for subscription %u",
495 subid);
496 snprintf(bgw.bgw_type, BGW_MAXLEN, "logical replication apply worker");
497 break;
498
500 snprintf(bgw.bgw_function_name, BGW_MAXLEN, "ParallelApplyWorkerMain");
502 "logical replication parallel apply worker for subscription %u",
503 subid);
504 snprintf(bgw.bgw_type, BGW_MAXLEN, "logical replication parallel worker");
505
506 memcpy(bgw.bgw_extra, &subworker_dsm, sizeof(dsm_handle));
507 break;
508
510 snprintf(bgw.bgw_function_name, BGW_MAXLEN, "TablesyncWorkerMain");
512 "logical replication tablesync worker for subscription %u sync %u",
513 subid,
514 relid);
515 snprintf(bgw.bgw_type, BGW_MAXLEN, "logical replication tablesync worker");
516 break;
517
519 /* Should never happen. */
520 elog(ERROR, "unknown worker type");
521 }
522
525 bgw.bgw_main_arg = Int32GetDatum(slot);
526
527 if (!RegisterDynamicBackgroundWorker(&bgw, &bgw_handle))
528 {
529 /* Failed to start worker, so clean up the worker slot. */
530 LWLockAcquire(LogicalRepWorkerLock, LW_EXCLUSIVE);
531 Assert(generation == worker->generation);
533 LWLockRelease(LogicalRepWorkerLock);
534
536 (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
537 errmsg("out of background worker slots"),
538 errhint("You might need to increase \"%s\".", "max_worker_processes")));
539 return false;
540 }
541
542 /* Now wait until it attaches. */
543 return WaitForReplicationWorkerAttach(worker, generation, bgw_handle);
544}
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Definition: timestamp.c:1781
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1645
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1609
bool RegisterDynamicBackgroundWorker(BackgroundWorker *worker, BackgroundWorkerHandle **handle)
Definition: bgworker.c:1046
#define BGW_NEVER_RESTART
Definition: bgworker.h:85
@ BgWorkerStart_RecoveryFinished
Definition: bgworker.h:81
#define BGWORKER_BACKEND_DATABASE_CONNECTION
Definition: bgworker.h:60
#define BGWORKER_SHMEM_ACCESS
Definition: bgworker.h:53
#define BGW_MAXLEN
Definition: bgworker.h:86
#define OidIsValid(objectId)
Definition: c.h:775
int64 TimestampTz
Definition: timestamp.h:39
#define TIMESTAMP_NOBEGIN(j)
Definition: timestamp.h:159
uint32 dsm_handle
Definition: dsm_impl.h:55
#define DSM_HANDLE_INVALID
Definition: dsm_impl.h:58
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1161
int errhint(const char *fmt,...)
Definition: elog.c:1321
int MyProcPid
Definition: globals.c:47
static int logicalrep_pa_worker_count(Oid subid)
Definition: launcher.c:898
int max_sync_workers_per_subscription
Definition: launcher.c:53
static bool WaitForReplicationWorkerAttach(LogicalRepWorker *worker, uint16 generation, BackgroundWorkerHandle *handle)
Definition: launcher.c:181
int logicalrep_sync_worker_count(Oid subid)
Definition: launcher.c:874
int max_parallel_apply_workers_per_subscription
Definition: launcher.c:54
static void logicalrep_worker_cleanup(LogicalRepWorker *worker)
Definition: launcher.c:812
#define InvalidPid
Definition: miscadmin.h:32
int max_active_replication_origins
Definition: origin.c:104
NameData subname
#define snprintf
Definition: port.h:239
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222
ReplicationSlot * MyReplicationSlot
Definition: slot.c:148
char bgw_function_name[BGW_MAXLEN]
Definition: bgworker.h:97
Datum bgw_main_arg
Definition: bgworker.h:98
char bgw_name[BGW_MAXLEN]
Definition: bgworker.h:91
int bgw_restart_time
Definition: bgworker.h:95
char bgw_type[BGW_MAXLEN]
Definition: bgworker.h:92
BgWorkerStartTime bgw_start_time
Definition: bgworker.h:94
char bgw_extra[BGW_EXTRALEN]
Definition: bgworker.h:99
pid_t bgw_notify_pid
Definition: bgworker.h:100
char bgw_library_name[MAXPGPATH]
Definition: bgworker.h:96
XLogRecPtr relstate_lsn
TimestampTz last_recv_time
TimestampTz launch_time
TimestampTz reply_time
FileSet * stream_fileset
XLogRecPtr reply_lsn
TimestampTz last_send_time
TransactionId xmin
Definition: slot.h:96
ReplicationSlotPersistentData data
Definition: slot.h:192
#define InvalidTransactionId
Definition: transam.h:31
int wal_receiver_timeout
Definition: walreceiver.c:89
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28

References Assert(), BackgroundWorker::bgw_extra, BackgroundWorker::bgw_flags, BackgroundWorker::bgw_function_name, BackgroundWorker::bgw_library_name, BackgroundWorker::bgw_main_arg, BGW_MAXLEN, BackgroundWorker::bgw_name, BGW_NEVER_RESTART, BackgroundWorker::bgw_notify_pid, BackgroundWorker::bgw_restart_time, BackgroundWorker::bgw_start_time, BackgroundWorker::bgw_type, BGWORKER_BACKEND_DATABASE_CONNECTION, BGWORKER_SHMEM_ACCESS, BgWorkerStart_RecoveryFinished, ReplicationSlot::data, LogicalRepWorker::dbid, DEBUG1, DSM_HANDLE_INVALID, elog, ereport, errcode(), errhint(), errmsg(), errmsg_internal(), ERROR, LogicalRepWorker::generation, GetCurrentTimestamp(), i, LogicalRepWorker::in_use, Int32GetDatum(), InvalidPid, InvalidTransactionId, InvalidXLogRecPtr, LogicalRepWorker::last_lsn, LogicalRepWorker::last_recv_time, LogicalRepWorker::last_send_time, LogicalRepWorker::launch_time, LogicalRepWorker::leader_pid, logicalrep_pa_worker_count(), logicalrep_sync_worker_count(), logicalrep_worker_cleanup(), LogicalRepCtx, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), max_active_replication_origins, max_logical_replication_workers, max_parallel_apply_workers_per_subscription, max_sync_workers_per_subscription, MAXPGPATH, MyProcPid, MyReplicationSlot, now(), OidIsValid, LogicalRepWorker::oldest_nonremovable_xid, LogicalRepWorker::parallel_apply, LogicalRepWorker::proc, RegisterDynamicBackgroundWorker(), LogicalRepWorker::relid, LogicalRepWorker::relstate, LogicalRepWorker::relstate_lsn, LogicalRepWorker::reply_lsn, LogicalRepWorker::reply_time, snprintf, LogicalRepWorker::stream_fileset, LogicalRepWorker::subid, subname, TIMESTAMP_NOBEGIN, TimestampDifferenceExceeds(), LogicalRepWorker::type, LogicalRepWorker::userid, WaitForReplicationWorkerAttach(), wal_receiver_timeout, WARNING, LogicalRepCtxStruct::workers, WORKERTYPE_APPLY, WORKERTYPE_PARALLEL_APPLY, WORKERTYPE_TABLESYNC, WORKERTYPE_UNKNOWN, and ReplicationSlotPersistentData::xmin.

Referenced by ApplyLauncherMain(), pa_launch_parallel_worker(), and process_syncing_tables_for_apply().

◆ logicalrep_worker_stop()

void logicalrep_worker_stop ( Oid  subid,
Oid  relid 
)

Definition at line 633 of file launcher.c.

634{
635 LogicalRepWorker *worker;
636
637 LWLockAcquire(LogicalRepWorkerLock, LW_SHARED);
638
639 worker = logicalrep_worker_find(subid, relid, false);
640
641 if (worker)
642 {
644 logicalrep_worker_stop_internal(worker, SIGTERM);
645 }
646
647 LWLockRelease(LogicalRepWorkerLock);
648}
LogicalRepWorker * logicalrep_worker_find(Oid subid, Oid relid, bool only_running)
Definition: launcher.c:254

References Assert(), isParallelApplyWorker, logicalrep_worker_find(), logicalrep_worker_stop_internal(), LW_SHARED, LWLockAcquire(), and LWLockRelease().

Referenced by AlterSubscription_refresh(), and DropSubscription().

◆ logicalrep_worker_wakeup()

void logicalrep_worker_wakeup ( Oid  subid,
Oid  relid 
)

Definition at line 700 of file launcher.c.

701{
702 LogicalRepWorker *worker;
703
704 LWLockAcquire(LogicalRepWorkerLock, LW_SHARED);
705
706 worker = logicalrep_worker_find(subid, relid, true);
707
708 if (worker)
710
711 LWLockRelease(LogicalRepWorkerLock);
712}
void logicalrep_worker_wakeup_ptr(LogicalRepWorker *worker)
Definition: launcher.c:720

References logicalrep_worker_find(), logicalrep_worker_wakeup_ptr(), LW_SHARED, LWLockAcquire(), and LWLockRelease().

Referenced by apply_handle_stream_start(), and finish_sync_worker().

◆ logicalrep_worker_wakeup_ptr()

void logicalrep_worker_wakeup_ptr ( LogicalRepWorker worker)

Definition at line 720 of file launcher.c.

721{
722 Assert(LWLockHeldByMe(LogicalRepWorkerLock));
723
724 SetLatch(&worker->proc->procLatch);
725}
void SetLatch(Latch *latch)
Definition: latch.c:290
Latch procLatch
Definition: proc.h:186

References Assert(), LWLockHeldByMe(), LogicalRepWorker::proc, PGPROC::procLatch, and SetLatch().

Referenced by AtEOXact_LogicalRepWorkers(), logicalrep_worker_wakeup(), process_syncing_tables_for_apply(), and wait_for_worker_state_change().

◆ logicalrep_workers_find()

List * logicalrep_workers_find ( Oid  subid,
bool  only_running,
bool  acquire_lock 
)

Definition at line 286 of file launcher.c.

287{
288 int i;
289 List *res = NIL;
290
291 if (acquire_lock)
292 LWLockAcquire(LogicalRepWorkerLock, LW_SHARED);
293
294 Assert(LWLockHeldByMe(LogicalRepWorkerLock));
295
296 /* Search for attached worker for a given subscription id. */
297 for (i = 0; i < max_logical_replication_workers; i++)
298 {
300
301 if (w->in_use && w->subid == subid && (!only_running || w->proc))
302 res = lappend(res, w);
303 }
304
305 if (acquire_lock)
306 LWLockRelease(LogicalRepWorkerLock);
307
308 return res;
309}
List * lappend(List *list, void *datum)
Definition: list.c:339
Definition: pg_list.h:54

References Assert(), i, LogicalRepWorker::in_use, lappend(), LogicalRepCtx, LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), max_logical_replication_workers, NIL, LogicalRepWorker::proc, LogicalRepWorker::subid, and LogicalRepCtxStruct::workers.

Referenced by AlterSubscription(), AtEOXact_LogicalRepWorkers(), DropSubscription(), and logicalrep_worker_detach().

◆ maybe_reread_subscription()

void maybe_reread_subscription ( void  )

Definition at line 5007 of file worker.c.

5008{
5009 MemoryContext oldctx;
5011 bool started_tx = false;
5012
5013 /* When cache state is valid there is nothing to do here. */
5015 return;
5016
5017 /* This function might be called inside or outside of transaction. */
5018 if (!IsTransactionState())
5019 {
5021 started_tx = true;
5022 }
5023
5024 /* Ensure allocations in permanent context. */
5026
5028
5029 /*
5030 * Exit if the subscription was removed. This normally should not happen
5031 * as the worker gets killed during DROP SUBSCRIPTION.
5032 */
5033 if (!newsub)
5034 {
5035 ereport(LOG,
5036 (errmsg("logical replication worker for subscription \"%s\" will stop because the subscription was removed",
5037 MySubscription->name)));
5038
5039 /* Ensure we remove no-longer-useful entry for worker's start time */
5042
5043 proc_exit(0);
5044 }
5045
5046 /* Exit if the subscription was disabled. */
5047 if (!newsub->enabled)
5048 {
5049 ereport(LOG,
5050 (errmsg("logical replication worker for subscription \"%s\" will stop because the subscription was disabled",
5051 MySubscription->name)));
5052
5054 }
5055
5056 /* !slotname should never happen when enabled is true. */
5057 Assert(newsub->slotname);
5058
5059 /* two-phase cannot be altered while the worker is running */
5060 Assert(newsub->twophasestate == MySubscription->twophasestate);
5061
5062 /*
5063 * Exit if any parameter that affects the remote connection was changed.
5064 * The launcher will start a new worker but note that the parallel apply
5065 * worker won't restart if the streaming option's value is changed from
5066 * 'parallel' to any other value or the server decides not to stream the
5067 * in-progress transaction.
5068 */
5069 if (strcmp(newsub->conninfo, MySubscription->conninfo) != 0 ||
5070 strcmp(newsub->name, MySubscription->name) != 0 ||
5071 strcmp(newsub->slotname, MySubscription->slotname) != 0 ||
5072 newsub->binary != MySubscription->binary ||
5073 newsub->stream != MySubscription->stream ||
5074 newsub->passwordrequired != MySubscription->passwordrequired ||
5075 strcmp(newsub->origin, MySubscription->origin) != 0 ||
5076 newsub->owner != MySubscription->owner ||
5077 !equal(newsub->publications, MySubscription->publications))
5078 {
5080 ereport(LOG,
5081 (errmsg("logical replication parallel apply worker for subscription \"%s\" will stop because of a parameter change",
5082 MySubscription->name)));
5083 else
5084 ereport(LOG,
5085 (errmsg("logical replication worker for subscription \"%s\" will restart because of a parameter change",
5086 MySubscription->name)));
5087
5089 }
5090
5091 /*
5092 * Exit if the subscription owner's superuser privileges have been
5093 * revoked.
5094 */
5095 if (!newsub->ownersuperuser && MySubscription->ownersuperuser)
5096 {
5098 ereport(LOG,
5099 errmsg("logical replication parallel apply worker for subscription \"%s\" will stop because the subscription owner's superuser privileges have been revoked",
5101 else
5102 ereport(LOG,
5103 errmsg("logical replication worker for subscription \"%s\" will restart because the subscription owner's superuser privileges have been revoked",
5105
5107 }
5108
5109 /* Check for other changes that should never happen too. */
5110 if (newsub->dbid != MySubscription->dbid)
5111 {
5112 elog(ERROR, "subscription %u changed unexpectedly",
5114 }
5115
5116 /* Clean old subscription info and switch to new one. */
5119
5120 MemoryContextSwitchTo(oldctx);
5121
5122 /* Change synchronous commit according to the user's wishes */
5123 SetConfigOption("synchronous_commit", MySubscription->synccommit,
5125
5126 if (started_tx)
5128
5129 MySubscriptionValid = true;
5130}
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:223
void FreeSubscription(Subscription *sub)
static color newsub(struct colormap *cm, color co)
Definition: regc_color.c:389
bool IsTransactionState(void)
Definition: xact.c:387

References am_leader_apply_worker(), am_parallel_apply_worker(), apply_worker_exit(), ApplyContext, ApplyLauncherForgetWorkerStartTime(), Assert(), Subscription::binary, CommitTransactionCommand(), Subscription::conninfo, Subscription::dbid, elog, equal(), ereport, errmsg(), ERROR, FreeSubscription(), GetSubscription(), IsTransactionState(), LOG, MemoryContextSwitchTo(), MyLogicalRepWorker, MySubscription, MySubscriptionValid, Subscription::name, newsub(), Subscription::origin, Subscription::owner, Subscription::ownersuperuser, Subscription::passwordrequired, PGC_BACKEND, PGC_S_OVERRIDE, proc_exit(), Subscription::publications, SetConfigOption(), Subscription::slotname, StartTransactionCommand(), Subscription::stream, LogicalRepWorker::subid, Subscription::synccommit, and Subscription::twophasestate.

Referenced by apply_handle_commit_internal(), begin_replication_step(), LogicalRepApplyLoop(), and pa_can_start().

◆ pa_allocate_worker()

void pa_allocate_worker ( TransactionId  xid)

Definition at line 471 of file applyparallelworker.c.

472{
473 bool found;
474 ParallelApplyWorkerInfo *winfo = NULL;
476
477 if (!pa_can_start())
478 return;
479
481 if (!winfo)
482 return;
483
484 /* First time through, initialize parallel apply worker state hashtable. */
486 {
487 HASHCTL ctl;
488
489 MemSet(&ctl, 0, sizeof(ctl));
490 ctl.keysize = sizeof(TransactionId);
491 ctl.entrysize = sizeof(ParallelApplyWorkerEntry);
492 ctl.hcxt = ApplyContext;
493
494 ParallelApplyTxnHash = hash_create("logical replication parallel apply workers hash",
495 16, &ctl,
497 }
498
499 /* Create an entry for the requested transaction. */
500 entry = hash_search(ParallelApplyTxnHash, &xid, HASH_ENTER, &found);
501 if (found)
502 elog(ERROR, "hash table corrupted");
503
504 /* Update the transaction information in shared memory. */
505 SpinLockAcquire(&winfo->shared->mutex);
507 winfo->shared->xid = xid;
508 SpinLockRelease(&winfo->shared->mutex);
509
510 winfo->in_use = true;
511 winfo->serialize_changes = false;
512 entry->winfo = winfo;
513}
struct ParallelApplyWorkerEntry ParallelApplyWorkerEntry
static bool pa_can_start(void)
static HTAB * ParallelApplyTxnHash
static ParallelApplyWorkerInfo * pa_launch_parallel_worker(void)
#define MemSet(start, val, len)
Definition: c.h:1020
uint32 TransactionId
Definition: c.h:658
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:358
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
tree ctl
Definition: radixtree.h:1838
ParallelApplyWorkerInfo * winfo
ParallelTransState xact_state

References ApplyContext, ctl, elog, ERROR, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), ParallelApplyWorkerInfo::in_use, MemSet, ParallelApplyWorkerShared::mutex, pa_can_start(), pa_launch_parallel_worker(), PARALLEL_TRANS_UNKNOWN, ParallelApplyTxnHash, ParallelApplyWorkerInfo::serialize_changes, ParallelApplyWorkerInfo::shared, SpinLockAcquire, SpinLockRelease, ParallelApplyWorkerEntry::winfo, ParallelApplyWorkerShared::xact_state, and ParallelApplyWorkerShared::xid.

Referenced by apply_handle_stream_start().

◆ pa_decr_and_wait_stream_block()

void pa_decr_and_wait_stream_block ( void  )

Definition at line 1599 of file applyparallelworker.c.

1600{
1602
1603 /*
1604 * It is only possible to not have any pending stream chunks when we are
1605 * applying spooled messages.
1606 */
1608 {
1610 return;
1611
1612 elog(ERROR, "invalid pending streaming chunk 0");
1613 }
1614
1616 {
1619 }
1620}
void pa_unlock_stream(TransactionId xid, LOCKMODE lockmode)
void pa_lock_stream(TransactionId xid, LOCKMODE lockmode)
static bool pa_has_spooled_message_pending()
ParallelApplyWorkerShared * MyParallelShared
static uint32 pg_atomic_sub_fetch_u32(volatile pg_atomic_uint32 *ptr, int32 sub_)
Definition: atomics.h:437
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:237
pg_atomic_uint32 pending_stream_count

References AccessShareLock, am_parallel_apply_worker(), Assert(), elog, ERROR, MyParallelShared, pa_has_spooled_message_pending(), pa_lock_stream(), pa_unlock_stream(), ParallelApplyWorkerShared::pending_stream_count, pg_atomic_read_u32(), pg_atomic_sub_fetch_u32(), and ParallelApplyWorkerShared::xid.

Referenced by apply_handle_stream_abort(), and apply_handle_stream_stop().

◆ pa_detach_all_error_mq()

void pa_detach_all_error_mq ( void  )

Definition at line 623 of file applyparallelworker.c.

624{
625 ListCell *lc;
626
627 foreach(lc, ParallelApplyWorkerPool)
628 {
630
631 if (winfo->error_mq_handle)
632 {
634 winfo->error_mq_handle = NULL;
635 }
636 }
637}
static List * ParallelApplyWorkerPool
#define lfirst(lc)
Definition: pg_list.h:172

References ParallelApplyWorkerInfo::error_mq_handle, lfirst, ParallelApplyWorkerPool, and shm_mq_detach().

Referenced by logicalrep_worker_detach().

◆ pa_find_worker()

ParallelApplyWorkerInfo * pa_find_worker ( TransactionId  xid)

Definition at line 519 of file applyparallelworker.c.

520{
521 bool found;
523
524 if (!TransactionIdIsValid(xid))
525 return NULL;
526
528 return NULL;
529
530 /* Return the cached parallel apply worker if valid. */
532 return stream_apply_worker;
533
534 /* Find an entry for the requested transaction. */
535 entry = hash_search(ParallelApplyTxnHash, &xid, HASH_FIND, &found);
536 if (found)
537 {
538 /* The worker must not have exited. */
539 Assert(entry->winfo->in_use);
540 return entry->winfo;
541 }
542
543 return NULL;
544}
static ParallelApplyWorkerInfo * stream_apply_worker
@ HASH_FIND
Definition: hsearch.h:113

References Assert(), HASH_FIND, hash_search(), ParallelApplyWorkerInfo::in_use, ParallelApplyTxnHash, stream_apply_worker, TransactionIdIsValid, and ParallelApplyWorkerEntry::winfo.

Referenced by get_transaction_apply_action().

◆ pa_lock_stream()

void pa_lock_stream ( TransactionId  xid,
LOCKMODE  lockmode 
)

◆ pa_lock_transaction()

void pa_lock_transaction ( TransactionId  xid,
LOCKMODE  lockmode 
)

◆ pa_reset_subtrans()

void pa_reset_subtrans ( void  )

Definition at line 1410 of file applyparallelworker.c.

1411{
1412 /*
1413 * We don't need to free this explicitly as the allocated memory will be
1414 * freed at the transaction end.
1415 */
1416 subxactlist = NIL;
1417}
static List * subxactlist

References NIL, and subxactlist.

Referenced by apply_handle_stream_commit(), apply_handle_stream_prepare(), and pa_stream_abort().

◆ pa_send_data()

bool pa_send_data ( ParallelApplyWorkerInfo winfo,
Size  nbytes,
const void *  data 
)

Definition at line 1154 of file applyparallelworker.c.

1155{
1156 int rc;
1157 shm_mq_result result;
1158 TimestampTz startTime = 0;
1159
1161 Assert(!winfo->serialize_changes);
1162
1163 /*
1164 * We don't try to send data to parallel worker for 'immediate' mode. This
1165 * is primarily used for testing purposes.
1166 */
1168 return false;
1169
1170/*
1171 * This timeout is a bit arbitrary but testing revealed that it is sufficient
1172 * to send the message unless the parallel apply worker is waiting on some
1173 * lock or there is a serious resource crunch. See the comments atop this file
1174 * to know why we are using a non-blocking way to send the message.
1175 */
1176#define SHM_SEND_RETRY_INTERVAL_MS 1000
1177#define SHM_SEND_TIMEOUT_MS (10000 - SHM_SEND_RETRY_INTERVAL_MS)
1178
1179 for (;;)
1180 {
1181 result = shm_mq_send(winfo->mq_handle, nbytes, data, true, true);
1182
1183 if (result == SHM_MQ_SUCCESS)
1184 return true;
1185 else if (result == SHM_MQ_DETACHED)
1186 ereport(ERROR,
1187 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1188 errmsg("could not send data to shared-memory queue")));
1189
1190 Assert(result == SHM_MQ_WOULD_BLOCK);
1191
1192 /* Wait before retrying. */
1193 rc = WaitLatch(MyLatch,
1196 WAIT_EVENT_LOGICAL_APPLY_SEND_DATA);
1197
1198 if (rc & WL_LATCH_SET)
1199 {
1202 }
1203
1204 if (startTime == 0)
1205 startTime = GetCurrentTimestamp();
1206 else if (TimestampDifferenceExceeds(startTime, GetCurrentTimestamp(),
1208 return false;
1209 }
1210}
#define SHM_SEND_TIMEOUT_MS
#define SHM_SEND_RETRY_INTERVAL_MS
#define unlikely(x)
Definition: c.h:403
struct Latch * MyLatch
Definition: globals.c:63
void ResetLatch(Latch *latch)
Definition: latch.c:374
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition: latch.c:172
const void * data
int debug_logical_replication_streaming
@ DEBUG_LOGICAL_REP_STREAMING_IMMEDIATE
Definition: reorderbuffer.h:34
shm_mq_result shm_mq_send(shm_mq_handle *mqh, Size nbytes, const void *data, bool nowait, bool force_flush)
Definition: shm_mq.c:329
shm_mq_result
Definition: shm_mq.h:37
@ SHM_MQ_SUCCESS
Definition: shm_mq.h:38
@ SHM_MQ_WOULD_BLOCK
Definition: shm_mq.h:39
@ SHM_MQ_DETACHED
Definition: shm_mq.h:40
shm_mq_handle * mq_handle
#define WL_TIMEOUT
Definition: waiteventset.h:37
#define WL_EXIT_ON_PM_DEATH
Definition: waiteventset.h:39
#define WL_LATCH_SET
Definition: waiteventset.h:34

References Assert(), CHECK_FOR_INTERRUPTS, data, DEBUG_LOGICAL_REP_STREAMING_IMMEDIATE, debug_logical_replication_streaming, ereport, errcode(), errmsg(), ERROR, GetCurrentTimestamp(), IsTransactionState(), ParallelApplyWorkerInfo::mq_handle, MyLatch, ResetLatch(), ParallelApplyWorkerInfo::serialize_changes, SHM_MQ_DETACHED, shm_mq_send(), SHM_MQ_SUCCESS, SHM_MQ_WOULD_BLOCK, SHM_SEND_RETRY_INTERVAL_MS, SHM_SEND_TIMEOUT_MS, TimestampDifferenceExceeds(), unlikely, WaitLatch(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, and WL_TIMEOUT.

Referenced by apply_handle_stream_abort(), apply_handle_stream_commit(), apply_handle_stream_prepare(), apply_handle_stream_start(), apply_handle_stream_stop(), and handle_streamed_transaction().

◆ pa_set_fileset_state()

◆ pa_set_stream_apply_worker()

void pa_set_stream_apply_worker ( ParallelApplyWorkerInfo winfo)

Definition at line 1342 of file applyparallelworker.c.

1343{
1344 stream_apply_worker = winfo;
1345}

References stream_apply_worker.

Referenced by apply_handle_stream_start(), and apply_handle_stream_stop().

◆ pa_set_xact_state()

void pa_set_xact_state ( ParallelApplyWorkerShared wshared,
ParallelTransState  xact_state 
)

◆ pa_start_subtrans()

void pa_start_subtrans ( TransactionId  current_xid,
TransactionId  top_xid 
)

Definition at line 1370 of file applyparallelworker.c.

1371{
1372 if (current_xid != top_xid &&
1373 !list_member_xid(subxactlist, current_xid))
1374 {
1375 MemoryContext oldctx;
1376 char spname[NAMEDATALEN];
1377
1378 pa_savepoint_name(MySubscription->oid, current_xid,
1379 spname, sizeof(spname));
1380
1381 elog(DEBUG1, "defining savepoint %s in logical replication parallel apply worker", spname);
1382
1383 /* We must be in transaction block to define the SAVEPOINT. */
1384 if (!IsTransactionBlock())
1385 {
1386 if (!IsTransactionState())
1388
1391 }
1392
1393 DefineSavepoint(spname);
1394
1395 /*
1396 * CommitTransactionCommand is needed to start a subtransaction after
1397 * issuing a SAVEPOINT inside a transaction block (see
1398 * StartSubTransaction()).
1399 */
1401
1403 subxactlist = lappend_xid(subxactlist, current_xid);
1404 MemoryContextSwitchTo(oldctx);
1405 }
1406}
static void pa_savepoint_name(Oid suboid, TransactionId xid, char *spname, Size szsp)
List * lappend_xid(List *list, TransactionId datum)
Definition: list.c:393
bool list_member_xid(const List *list, TransactionId datum)
Definition: list.c:742
#define NAMEDATALEN
void DefineSavepoint(const char *name)
Definition: xact.c:4385
bool IsTransactionBlock(void)
Definition: xact.c:4983
void BeginTransactionBlock(void)
Definition: xact.c:3936

References BeginTransactionBlock(), CommitTransactionCommand(), DEBUG1, DefineSavepoint(), elog, IsTransactionBlock(), IsTransactionState(), lappend_xid(), list_member_xid(), MemoryContextSwitchTo(), MySubscription, NAMEDATALEN, Subscription::oid, pa_savepoint_name(), StartTransactionCommand(), subxactlist, and TopTransactionContext.

Referenced by handle_streamed_transaction().

◆ pa_stream_abort()

void pa_stream_abort ( LogicalRepStreamAbortData abort_data)

Definition at line 1424 of file applyparallelworker.c.

1425{
1426 TransactionId xid = abort_data->xid;
1427 TransactionId subxid = abort_data->subxid;
1428
1429 /*
1430 * Update origin state so we can restart streaming from correct position
1431 * in case of crash.
1432 */
1435
1436 /*
1437 * If the two XIDs are the same, it's in fact abort of toplevel xact, so
1438 * just free the subxactlist.
1439 */
1440 if (subxid == xid)
1441 {
1443
1444 /*
1445 * Release the lock as we might be processing an empty streaming
1446 * transaction in which case the lock won't be released during
1447 * transaction rollback.
1448 *
1449 * Note that it's ok to release the transaction lock before aborting
1450 * the transaction because even if the parallel apply worker dies due
1451 * to crash or some other reason, such a transaction would still be
1452 * considered aborted.
1453 */
1455
1457
1458 if (IsTransactionBlock())
1459 {
1460 EndTransactionBlock(false);
1462 }
1463
1465
1467 }
1468 else
1469 {
1470 /* OK, so it's a subxact. Rollback to the savepoint. */
1471 int i;
1472 char spname[NAMEDATALEN];
1473
1474 pa_savepoint_name(MySubscription->oid, subxid, spname, sizeof(spname));
1475
1476 elog(DEBUG1, "rolling back to savepoint %s in logical replication parallel apply worker", spname);
1477
1478 /*
1479 * Search the subxactlist, determine the offset tracked for the
1480 * subxact, and truncate the list.
1481 *
1482 * Note that for an empty sub-transaction we won't find the subxid
1483 * here.
1484 */
1485 for (i = list_length(subxactlist) - 1; i >= 0; i--)
1486 {
1488
1489 if (xid_tmp == subxid)
1490 {
1491 RollbackToSavepoint(spname);
1494 break;
1495 }
1496 }
1497 }
1498}
void pa_set_xact_state(ParallelApplyWorkerShared *wshared, ParallelTransState xact_state)
void pa_reset_subtrans(void)
void pa_unlock_transaction(TransactionId xid, LOCKMODE lockmode)
@ STATE_IDLE
List * list_truncate(List *list, int new_size)
Definition: list.c:631
#define AccessExclusiveLock
Definition: lockdefs.h:43
TimestampTz replorigin_session_origin_timestamp
Definition: origin.c:165
XLogRecPtr replorigin_session_origin_lsn
Definition: origin.c:164
static int list_length(const List *l)
Definition: pg_list.h:152
static ListCell * list_nth_cell(const List *list, int n)
Definition: pg_list.h:277
#define lfirst_xid(lc)
Definition: pg_list.h:175
void RollbackToSavepoint(const char *name)
Definition: xact.c:4579
bool EndTransactionBlock(bool chain)
Definition: xact.c:4056
void AbortCurrentTransaction(void)
Definition: xact.c:3463

References LogicalRepStreamAbortData::abort_lsn, LogicalRepStreamAbortData::abort_time, AbortCurrentTransaction(), AccessExclusiveLock, CommitTransactionCommand(), DEBUG1, elog, EndTransactionBlock(), i, IsTransactionBlock(), lfirst_xid, list_length(), list_nth_cell(), list_truncate(), MyParallelShared, MySubscription, NAMEDATALEN, Subscription::oid, pa_reset_subtrans(), pa_savepoint_name(), pa_set_xact_state(), pa_unlock_transaction(), PARALLEL_TRANS_FINISHED, pgstat_report_activity(), replorigin_session_origin_lsn, replorigin_session_origin_timestamp, RollbackToSavepoint(), STATE_IDLE, subxactlist, LogicalRepStreamAbortData::subxid, and LogicalRepStreamAbortData::xid.

Referenced by apply_handle_stream_abort().

◆ pa_switch_to_partial_serialize()

void pa_switch_to_partial_serialize ( ParallelApplyWorkerInfo winfo,
bool  stream_locked 
)

Definition at line 1219 of file applyparallelworker.c.

1221{
1222 ereport(LOG,
1223 (errmsg("logical replication apply worker will serialize the remaining changes of remote transaction %u to a file",
1224 winfo->shared->xid)));
1225
1226 /*
1227 * The parallel apply worker could be stuck for some reason (say waiting
1228 * on some lock by other backend), so stop trying to send data directly to
1229 * it and start serializing data to the file instead.
1230 */
1231 winfo->serialize_changes = true;
1232
1233 /* Initialize the stream fileset. */
1234 stream_start_internal(winfo->shared->xid, true);
1235
1236 /*
1237 * Acquires the stream lock if not already to make sure that the parallel
1238 * apply worker will wait for the leader to release the stream lock until
1239 * the end of the transaction.
1240 */
1241 if (!stream_locked)
1243
1245}
void pa_set_fileset_state(ParallelApplyWorkerShared *wshared, PartialFileSetState fileset_state)
void stream_start_internal(TransactionId xid, bool first_segment)
Definition: worker.c:1666

References AccessExclusiveLock, ereport, errmsg(), FS_SERIALIZE_IN_PROGRESS, LOG, pa_lock_stream(), pa_set_fileset_state(), ParallelApplyWorkerInfo::serialize_changes, ParallelApplyWorkerInfo::shared, stream_start_internal(), and ParallelApplyWorkerShared::xid.

Referenced by apply_handle_stream_abort(), apply_handle_stream_commit(), apply_handle_stream_prepare(), apply_handle_stream_start(), apply_handle_stream_stop(), and handle_streamed_transaction().

◆ pa_unlock_stream()

void pa_unlock_stream ( TransactionId  xid,
LOCKMODE  lockmode 
)

◆ pa_unlock_transaction()

◆ pa_xact_finish()

void pa_xact_finish ( ParallelApplyWorkerInfo winfo,
XLogRecPtr  remote_lsn 
)

Definition at line 1626 of file applyparallelworker.c.

1627{
1629
1630 /*
1631 * Unlock the shared object lock so that parallel apply worker can
1632 * continue to receive and apply changes.
1633 */
1635
1636 /*
1637 * Wait for that worker to finish. This is necessary to maintain commit
1638 * order which avoids failures due to transaction dependencies and
1639 * deadlocks.
1640 */
1642
1643 if (!XLogRecPtrIsInvalid(remote_lsn))
1644 store_flush_position(remote_lsn, winfo->shared->last_commit_end);
1645
1646 pa_free_worker(winfo);
1647}
static void pa_free_worker(ParallelApplyWorkerInfo *winfo)
static void pa_wait_for_xact_finish(ParallelApplyWorkerInfo *winfo)
void store_flush_position(XLogRecPtr remote_lsn, XLogRecPtr local_lsn)
Definition: worker.c:3911

References AccessExclusiveLock, am_leader_apply_worker(), Assert(), ParallelApplyWorkerShared::last_commit_end, pa_free_worker(), pa_unlock_stream(), pa_wait_for_xact_finish(), ParallelApplyWorkerInfo::shared, store_flush_position(), ParallelApplyWorkerShared::xid, and XLogRecPtrIsInvalid.

Referenced by apply_handle_stream_abort(), apply_handle_stream_commit(), and apply_handle_stream_prepare().

◆ process_syncing_tables()

void process_syncing_tables ( XLogRecPtr  current_lsn)

Definition at line 696 of file tablesync.c.

697{
698 switch (MyLogicalRepWorker->type)
699 {
701
702 /*
703 * Skip for parallel apply workers because they only operate on
704 * tables that are in a READY state. See pa_can_start() and
705 * should_apply_changes_for_rel().
706 */
707 break;
708
711 break;
712
713 case WORKERTYPE_APPLY:
715 break;
716
718 /* Should never happen. */
719 elog(ERROR, "Unknown worker type");
720 }
721}
static void process_syncing_tables_for_apply(XLogRecPtr current_lsn)
Definition: tablesync.c:418
static void process_syncing_tables_for_sync(XLogRecPtr current_lsn)
Definition: tablesync.c:294

References elog, ERROR, MyLogicalRepWorker, process_syncing_tables_for_apply(), process_syncing_tables_for_sync(), LogicalRepWorker::type, WORKERTYPE_APPLY, WORKERTYPE_PARALLEL_APPLY, WORKERTYPE_TABLESYNC, and WORKERTYPE_UNKNOWN.

Referenced by apply_handle_commit(), apply_handle_commit_prepared(), apply_handle_prepare(), apply_handle_rollback_prepared(), apply_handle_stream_commit(), apply_handle_stream_prepare(), and LogicalRepApplyLoop().

◆ ReplicationOriginNameForLogicalRep()

void ReplicationOriginNameForLogicalRep ( Oid  suboid,
Oid  relid,
char *  originname,
Size  szoriginname 
)

Definition at line 641 of file worker.c.

643{
644 if (OidIsValid(relid))
645 {
646 /* Replication origin name for tablesync workers. */
647 snprintf(originname, szoriginname, "pg_%u_%u", suboid, relid);
648 }
649 else
650 {
651 /* Replication origin name for non-tablesync workers. */
652 snprintf(originname, szoriginname, "pg_%u", suboid);
653 }
654}

References OidIsValid, and snprintf.

Referenced by AlterSubscription(), AlterSubscription_refresh(), binary_upgrade_replorigin_advance(), CreateSubscription(), DropSubscription(), LogicalRepSyncTableStart(), ParallelApplyWorkerMain(), process_syncing_tables_for_apply(), process_syncing_tables_for_sync(), run_apply_worker(), and run_tablesync_worker().

◆ set_apply_error_context_origin()

void set_apply_error_context_origin ( char *  originname)

Definition at line 6260 of file worker.c.

6261{
6263 originname);
6264}
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1746

References apply_error_callback_arg, ApplyContext, MemoryContextStrdup(), and ApplyErrorCallbackArg::origin_name.

Referenced by ParallelApplyWorkerMain(), run_apply_worker(), and run_tablesync_worker().

◆ set_stream_options()

void set_stream_options ( WalRcvStreamOptions options,
char *  slotname,
XLogRecPtr origin_startpos 
)

Definition at line 5483 of file worker.c.

5486{
5487 int server_version;
5488
5489 options->logical = true;
5490 options->startpoint = *origin_startpos;
5491 options->slotname = slotname;
5492
5494 options->proto.logical.proto_version =
5499
5500 options->proto.logical.publication_names = MySubscription->publications;
5501 options->proto.logical.binary = MySubscription->binary;
5502
5503 /*
5504 * Assign the appropriate option value for streaming option according to
5505 * the 'streaming' mode and the publisher's ability to support that mode.
5506 */
5507 if (server_version >= 160000 &&
5508 MySubscription->stream == LOGICALREP_STREAM_PARALLEL)
5509 {
5510 options->proto.logical.streaming_str = "parallel";
5512 }
5513 else if (server_version >= 140000 &&
5514 MySubscription->stream != LOGICALREP_STREAM_OFF)
5515 {
5516 options->proto.logical.streaming_str = "on";
5518 }
5519 else
5520 {
5521 options->proto.logical.streaming_str = NULL;
5523 }
5524
5525 options->proto.logical.twophase = false;
5526 options->proto.logical.origin = pstrdup(MySubscription->origin);
5527}
WalReceiverConn * LogRepWorkerWalRcvConn
Definition: worker.c:477
#define LOGICALREP_PROTO_STREAM_PARALLEL_VERSION_NUM
Definition: logicalproto.h:44
#define LOGICALREP_PROTO_STREAM_VERSION_NUM
Definition: logicalproto.h:42
#define LOGICALREP_PROTO_TWOPHASE_VERSION_NUM
Definition: logicalproto.h:43
#define LOGICALREP_PROTO_VERSION_NUM
Definition: logicalproto.h:41
char * pstrdup(const char *in)
Definition: mcxt.c:1759
static int server_version
Definition: pg_dumpall.c:109
#define walrcv_server_version(conn)
Definition: walreceiver.h:447

References Subscription::binary, LOGICALREP_PROTO_STREAM_PARALLEL_VERSION_NUM, LOGICALREP_PROTO_STREAM_VERSION_NUM, LOGICALREP_PROTO_TWOPHASE_VERSION_NUM, LOGICALREP_PROTO_VERSION_NUM, LogRepWorkerWalRcvConn, MyLogicalRepWorker, MySubscription, Subscription::origin, LogicalRepWorker::parallel_apply, pstrdup(), Subscription::publications, server_version, Subscription::stream, and walrcv_server_version.

Referenced by run_apply_worker(), and run_tablesync_worker().

◆ SetupApplyOrSyncWorker()

void SetupApplyOrSyncWorker ( int  worker_slot)

Definition at line 5831 of file worker.c.

5832{
5833 /* Attach to slot */
5834 logicalrep_worker_attach(worker_slot);
5835
5837
5838 /* Setup signal handling */
5840 pqsignal(SIGTERM, die);
5842
5843 /*
5844 * We don't currently need any ResourceOwner in a walreceiver process, but
5845 * if we did, we could call CreateAuxProcessResourceOwner here.
5846 */
5847
5848 /* Initialise stats to a sanish value */
5851
5852 /* Load the libpq-specific functions */
5853 load_file("libpqwalreceiver", false);
5854
5856
5857 /*
5858 * Register a callback to reset the origin state before aborting any
5859 * pending transaction during shutdown (see ShutdownPostgres()). This will
5860 * avoid origin advancement for an in-complete transaction which could
5861 * otherwise lead to its loss as such a transaction won't be sent by the
5862 * server again.
5863 *
5864 * Note that even a LOG or DEBUG statement placed after setting the origin
5865 * state may process a shutdown signal before committing the current apply
5866 * operation. So, it is important to register such a callback here.
5867 */
5869
5870 /* Connect to the origin and start the replication. */
5871 elog(DEBUG1, "connecting to publisher using connection string \"%s\"",
5873
5874 /*
5875 * Setup callback for syscache so that we know when something changes in
5876 * the subscription relation state.
5877 */
5878 CacheRegisterSyscacheCallback(SUBSCRIPTIONRELMAP,
5880 (Datum) 0);
5881}
static void replorigin_reset(int code, Datum arg)
Definition: worker.c:5822
void InitializeLogRepWorker(void)
Definition: worker.c:5705
void BackgroundWorkerUnblockSignals(void)
Definition: bgworker.c:927
void load_file(const char *filename, bool restricted)
Definition: dfmgr.c:149
void SignalHandlerForConfigReload(SIGNAL_ARGS)
Definition: interrupt.c:61
void logicalrep_worker_attach(int slot)
Definition: launcher.c:731
#define die(msg)
#define pqsignal
Definition: port.h:531
void invalidate_syncing_table_states(Datum arg, int cacheid, uint32 hashvalue)
Definition: tablesync.c:280
#define SIGHUP
Definition: win32_port.h:158

References am_leader_apply_worker(), am_tablesync_worker(), Assert(), BackgroundWorkerUnblockSignals(), before_shmem_exit(), CacheRegisterSyscacheCallback(), Subscription::conninfo, DEBUG1, die, elog, GetCurrentTimestamp(), InitializeLogRepWorker(), invalidate_syncing_table_states(), LogicalRepWorker::last_recv_time, LogicalRepWorker::last_send_time, load_file(), logicalrep_worker_attach(), MyLogicalRepWorker, MySubscription, pqsignal, replorigin_reset(), LogicalRepWorker::reply_time, SIGHUP, and SignalHandlerForConfigReload().

Referenced by ApplyWorkerMain(), and TablesyncWorkerMain().

◆ start_apply()

void start_apply ( XLogRecPtr  origin_startpos)

Definition at line 5552 of file worker.c.

5553{
5554 PG_TRY();
5555 {
5556 LogicalRepApplyLoop(origin_startpos);
5557 }
5558 PG_CATCH();
5559 {
5560 /*
5561 * Reset the origin state to prevent the advancement of origin
5562 * progress if we fail to apply. Otherwise, this will result in
5563 * transaction loss as that transaction won't be sent again by the
5564 * server.
5565 */
5566 replorigin_reset(0, (Datum) 0);
5567
5570 else
5571 {
5572 /*
5573 * Report the worker failed while applying changes. Abort the
5574 * current transaction so that the stats message is sent in an
5575 * idle state.
5576 */
5579
5580 PG_RE_THROW();
5581 }
5582 }
5583 PG_END_TRY();
5584}
static void LogicalRepApplyLoop(XLogRecPtr last_received)
Definition: worker.c:3953
void DisableSubscriptionAndExit(void)
Definition: worker.c:5905
#define PG_RE_THROW()
Definition: elog.h:405
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define PG_CATCH(...)
Definition: elog.h:382

References AbortOutOfAnyTransaction(), am_tablesync_worker(), Subscription::disableonerr, DisableSubscriptionAndExit(), LogicalRepApplyLoop(), MySubscription, Subscription::oid, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgstat_report_subscription_error(), and replorigin_reset().

Referenced by run_apply_worker(), and run_tablesync_worker().

◆ store_flush_position()

void store_flush_position ( XLogRecPtr  remote_lsn,
XLogRecPtr  local_lsn 
)

Definition at line 3911 of file worker.c.

3912{
3913 FlushPosition *flushpos;
3914
3915 /*
3916 * Skip for parallel apply workers, because the lsn_mapping is maintained
3917 * by the leader apply worker.
3918 */
3920 return;
3921
3922 /* Need to do this in permanent context */
3924
3925 /* Track commit lsn */
3926 flushpos = (FlushPosition *) palloc(sizeof(FlushPosition));
3927 flushpos->local_end = local_lsn;
3928 flushpos->remote_end = remote_lsn;
3929
3930 dlist_push_tail(&lsn_mapping, &flushpos->node);
3932}
static dlist_head lsn_mapping
Definition: worker.c:308
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:364
dlist_node node
Definition: worker.c:303
XLogRecPtr remote_end
Definition: worker.c:305
XLogRecPtr local_end
Definition: worker.c:304

References am_parallel_apply_worker(), ApplyContext, ApplyMessageContext, dlist_push_tail(), FlushPosition::local_end, lsn_mapping, MemoryContextSwitchTo(), FlushPosition::node, palloc(), and FlushPosition::remote_end.

Referenced by apply_handle_commit_internal(), apply_handle_commit_prepared(), apply_handle_prepare(), apply_handle_rollback_prepared(), apply_handle_stream_prepare(), and pa_xact_finish().

◆ stream_cleanup_files()

void stream_cleanup_files ( Oid  subid,
TransactionId  xid 
)

Definition at line 5350 of file worker.c.

5351{
5352 char path[MAXPGPATH];
5353
5354 /* Delete the changes file. */
5355 changes_filename(path, subid, xid);
5357
5358 /* Delete the subxact file, if it exists. */
5359 subxact_filename(path, subid, xid);
5361}
static void subxact_filename(char *path, Oid subid, TransactionId xid)
Definition: worker.c:5329
void BufFileDeleteFileSet(FileSet *fileset, const char *name, bool missing_ok)
Definition: buffile.c:364

References BufFileDeleteFileSet(), changes_filename(), MAXPGPATH, MyLogicalRepWorker, LogicalRepWorker::stream_fileset, and subxact_filename().

Referenced by apply_handle_stream_commit(), apply_handle_stream_prepare(), pa_free_worker_info(), and stream_abort_internal().

◆ stream_start_internal()

void stream_start_internal ( TransactionId  xid,
bool  first_segment 
)

Definition at line 1666 of file worker.c.

1667{
1669
1670 /*
1671 * Initialize the worker's stream_fileset if we haven't yet. This will be
1672 * used for the entire duration of the worker so create it in a permanent
1673 * context. We create this on the very first streaming message from any
1674 * transaction and then use it for this and other streaming transactions.
1675 * Now, we could create a fileset at the start of the worker as well but
1676 * then we won't be sure that it will ever be used.
1677 */
1679 {
1680 MemoryContext oldctx;
1681
1683
1686
1687 MemoryContextSwitchTo(oldctx);
1688 }
1689
1690 /* Open the spool file for this transaction. */
1691 stream_open_file(MyLogicalRepWorker->subid, xid, first_segment);
1692
1693 /* If this is not the first segment, open existing subxact file. */
1694 if (!first_segment)
1696
1698}
static void stream_open_file(Oid subid, TransactionId xid, bool first_segment)
Definition: worker.c:5374
static void subxact_info_read(Oid subid, TransactionId xid)
Definition: worker.c:5200
void FileSetInit(FileSet *fileset)
Definition: fileset.c:52

References ApplyContext, begin_replication_step(), end_replication_step(), FileSetInit(), MemoryContextSwitchTo(), MyLogicalRepWorker, palloc(), LogicalRepWorker::stream_fileset, stream_open_file(), LogicalRepWorker::subid, and subxact_info_read().

Referenced by apply_handle_stream_start(), pa_switch_to_partial_serialize(), and stream_open_and_write_change().

◆ stream_stop_internal()

void stream_stop_internal ( TransactionId  xid)

Definition at line 1840 of file worker.c.

1841{
1842 /*
1843 * Serialize information about subxacts for the toplevel transaction, then
1844 * close the stream messages spool file.
1845 */
1848
1849 /* We must be in a valid transaction state */
1851
1852 /* Commit the per-stream transaction */
1854
1855 /* Reset per-stream context */
1857}
static void subxact_info_write(Oid subid, TransactionId xid)
Definition: worker.c:5151
static MemoryContext LogicalStreamingContext
Definition: worker.c:475

References Assert(), CommitTransactionCommand(), IsTransactionState(), LogicalStreamingContext, MemoryContextReset(), MyLogicalRepWorker, stream_close_file(), LogicalRepWorker::subid, and subxact_info_write().

Referenced by apply_handle_stream_stop(), and stream_open_and_write_change().

◆ UpdateTwoPhaseState()

void UpdateTwoPhaseState ( Oid  suboid,
char  new_state 
)

Definition at line 1821 of file tablesync.c.

1822{
1823 Relation rel;
1824 HeapTuple tup;
1825 bool nulls[Natts_pg_subscription];
1826 bool replaces[Natts_pg_subscription];
1827 Datum values[Natts_pg_subscription];
1828
1829 Assert(new_state == LOGICALREP_TWOPHASE_STATE_DISABLED ||
1830 new_state == LOGICALREP_TWOPHASE_STATE_PENDING ||
1831 new_state == LOGICALREP_TWOPHASE_STATE_ENABLED);
1832
1833 rel = table_open(SubscriptionRelationId, RowExclusiveLock);
1834 tup = SearchSysCacheCopy1(SUBSCRIPTIONOID, ObjectIdGetDatum(suboid));
1835 if (!HeapTupleIsValid(tup))
1836 elog(ERROR,
1837 "cache lookup failed for subscription oid %u",
1838 suboid);
1839
1840 /* Form a new tuple. */
1841 memset(values, 0, sizeof(values));
1842 memset(nulls, false, sizeof(nulls));
1843 memset(replaces, false, sizeof(replaces));
1844
1845 /* And update/set two_phase state */
1846 values[Anum_pg_subscription_subtwophasestate - 1] = CharGetDatum(new_state);
1847 replaces[Anum_pg_subscription_subtwophasestate - 1] = true;
1848
1849 tup = heap_modify_tuple(tup, RelationGetDescr(rel),
1850 values, nulls, replaces);
1851 CatalogTupleUpdate(rel, &tup->t_self, tup);
1852
1853 heap_freetuple(tup);
1855}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
#define RowExclusiveLock
Definition: lockdefs.h:38
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
static Datum CharGetDatum(char X)
Definition: postgres.h:132
#define RelationGetDescr(relation)
Definition: rel.h:540
ItemPointerData t_self
Definition: htup.h:65
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References Assert(), CatalogTupleUpdate(), CharGetDatum(), elog, ERROR, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, ObjectIdGetDatum(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, HeapTupleData::t_self, table_close(), table_open(), and values.

Referenced by CreateSubscription(), and run_apply_worker().

Variable Documentation

◆ apply_error_context_stack

PGDLLIMPORT ErrorContextCallback* apply_error_context_stack
extern

Definition at line 469 of file worker.c.

Referenced by LogicalRepApplyLoop(), and ProcessParallelApplyMessage().

◆ ApplyContext

◆ ApplyMessageContext

◆ in_remote_transaction

◆ InitializingApplyWorker

PGDLLIMPORT bool InitializingApplyWorker
extern

Definition at line 499 of file worker.c.

Referenced by ApplyWorkerMain(), logicalrep_worker_onexit(), and ParallelApplyWorkerMain().

◆ LogRepWorkerWalRcvConn

◆ MyLogicalRepWorker

◆ MyParallelShared

◆ MySubscription