PostgreSQL Source Code git master
Loading...
Searching...
No Matches
sequencesync.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/table.h"
#include "catalog/pg_sequence.h"
#include "catalog/pg_subscription_rel.h"
#include "commands/sequence.h"
#include "pgstat.h"
#include "postmaster/interrupt.h"
#include "replication/logicalworker.h"
#include "replication/worker_internal.h"
#include "storage/lwlock.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/guc.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/pg_lsn.h"
#include "utils/syscache.h"
#include "utils/usercontext.h"
Include dependency graph for sequencesync.c:

Go to the source code of this file.

Macros

#define REMOTE_SEQ_COL_COUNT   11
 
#define MAX_SEQUENCES_SYNC_PER_BATCH   100
 

Typedefs

typedef enum CopySeqResult CopySeqResult
 

Enumerations

enum  CopySeqResult {
  COPYSEQ_SUCCESS , COPYSEQ_MISMATCH , COPYSEQ_SUBSCRIBER_INSUFFICIENT_PERM , COPYSEQ_PUBLISHER_INSUFFICIENT_PERM ,
  COPYSEQ_SKIPPED
}
 

Functions

void ProcessSequencesForSync (void)
 
static void get_sequences_string (List *seqindexes, StringInfo buf)
 
static void report_sequence_errors (List *mismatched_seqs_idx, List *sub_insuffperm_seqs_idx, List *pub_insuffperm_seqs_idx, List *missing_seqs_idx)
 
static CopySeqResult get_and_validate_seq_info (TupleTableSlot *slot, Relation *sequence_rel, LogicalRepSequenceInfo **seqinfo, int *seqidx)
 
static CopySeqResult copy_sequence (LogicalRepSequenceInfo *seqinfo, Oid seqowner)
 
static void copy_sequences (WalReceiverConn *conn)
 
static void LogicalRepSyncSequences (void)
 
static void start_sequence_sync (void)
 
void SequenceSyncWorkerMain (Datum main_arg)
 

Variables

static Listseqinfos = NIL
 

Macro Definition Documentation

◆ MAX_SEQUENCES_SYNC_PER_BATCH

#define MAX_SEQUENCES_SYNC_PER_BATCH   100

◆ REMOTE_SEQ_COL_COUNT

#define REMOTE_SEQ_COL_COUNT   11

Definition at line 75 of file sequencesync.c.

Typedef Documentation

◆ CopySeqResult

Enumeration Type Documentation

◆ CopySeqResult

Enumerator
COPYSEQ_SUCCESS 
COPYSEQ_MISMATCH 
COPYSEQ_SUBSCRIBER_INSUFFICIENT_PERM 
COPYSEQ_PUBLISHER_INSUFFICIENT_PERM 
COPYSEQ_SKIPPED 

Definition at line 77 of file sequencesync.c.

78{
CopySeqResult
@ COPYSEQ_SUBSCRIBER_INSUFFICIENT_PERM
@ COPYSEQ_MISMATCH
@ COPYSEQ_SUCCESS
@ COPYSEQ_SKIPPED
@ COPYSEQ_PUBLISHER_INSUFFICIENT_PERM

Function Documentation

◆ copy_sequence()

static CopySeqResult copy_sequence ( LogicalRepSequenceInfo seqinfo,
Oid  seqowner 
)
static

Definition at line 375 of file sequencesync.c.

376{
380 Oid seqoid = seqinfo->localrelid;
381
382 /*
383 * If the user did not opt to run as the owner of the subscription
384 * ('run_as_owner'), then copy the sequence as the owner of the sequence.
385 */
386 if (!run_as_owner)
388
390
391 if (aclresult != ACLCHECK_OK)
392 {
393 if (!run_as_owner)
395
397 }
398
399 /*
400 * The log counter (log_cnt) tracks how many sequence values are still
401 * unused locally. It is only relevant to the local node and managed
402 * internally by nextval() when allocating new ranges. Since log_cnt does
403 * not affect the visible sequence state (like last_value or is_called)
404 * and is only used for local caching, it need not be copied to the
405 * subscriber during synchronization.
406 */
407 SetSequence(seqoid, seqinfo->last_value, seqinfo->is_called);
408
409 if (!run_as_owner)
411
412 /*
413 * Record the remote sequence's LSN in pg_subscription_rel and mark the
414 * sequence as READY.
415 */
417 seqinfo->page_lsn, false);
418
419 return COPYSEQ_SUCCESS;
420}
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
Definition aclchk.c:4105
Subscription * MySubscription
Definition worker.c:484
void SetSequence(Oid relid, int64 next, bool iscalled)
Definition sequence.c:946
Oid GetUserId(void)
Definition miscinit.c:470
#define ACL_UPDATE
Definition parsenodes.h:78
void UpdateSubscriptionRelState(Oid subid, Oid relid, char state, XLogRecPtr sublsn, bool already_locked)
unsigned int Oid
static int fb(int x)
void SwitchToUntrustedUser(Oid userid, UserContext *context)
Definition usercontext.c:33
void RestoreUserContext(UserContext *context)
Definition usercontext.c:87

References ACL_UPDATE, ACLCHECK_OK, COPYSEQ_SUBSCRIBER_INSUFFICIENT_PERM, COPYSEQ_SUCCESS, fb(), GetUserId(), MySubscription, Subscription::oid, pg_class_aclcheck(), RestoreUserContext(), Subscription::runasowner, SetSequence(), SwitchToUntrustedUser(), and UpdateSubscriptionRelState().

Referenced by copy_sequences().

◆ copy_sequences()

static void copy_sequences ( WalReceiverConn conn)
static

Definition at line 426 of file sequencesync.c.

427{
428 int cur_batch_base_index = 0;
435 StringInfoData cmd;
437
439 initStringInfo(&cmd);
440
441#define MAX_SEQUENCES_SYNC_PER_BATCH 100
442
443 elog(DEBUG1,
444 "logical replication sequence synchronization for subscription \"%s\" - total unsynchronized: %d",
446
448 {
451 int batch_size = 0;
452 int batch_succeeded_count = 0;
454 int batch_skipped_count = 0;
458
459 WalRcvExecResult *res;
460 TupleTableSlot *slot;
461
463
464 for (int idx = cur_batch_base_index; idx < n_seqinfos; idx++)
465 {
466 char *nspname_literal;
467 char *seqname_literal;
468
471
472 if (seqstr.len > 0)
474
477
478 appendStringInfo(&seqstr, "(%s, %s, %d)",
480
481 if (++batch_size == MAX_SEQUENCES_SYNC_PER_BATCH)
482 break;
483 }
484
485 /*
486 * We deliberately avoid acquiring a local lock on the sequence before
487 * querying the publisher to prevent potential distributed deadlocks
488 * in bi-directional replication setups.
489 *
490 * Example scenario:
491 *
492 * - On each node, a background worker acquires a lock on a sequence
493 * as part of a sync operation.
494 *
495 * - Concurrently, a user transaction attempts to alter the same
496 * sequence, waiting on the background worker's lock.
497 *
498 * - Meanwhile, a query from the other node tries to access metadata
499 * that depends on the completion of the alter operation.
500 *
501 * - This creates a circular wait across nodes:
502 *
503 * Node-1: Query -> waits on Alter -> waits on Sync Worker
504 *
505 * Node-2: Query -> waits on Alter -> waits on Sync Worker
506 *
507 * Since each node only sees part of the wait graph, the deadlock may
508 * go undetected, leading to indefinite blocking.
509 *
510 * Note: Each entry in VALUES includes an index 'seqidx' that
511 * represents the sequence's position in the local 'seqinfos' list.
512 * This index is propagated to the query results and later used to
513 * directly map the fetched publisher sequence rows back to their
514 * corresponding local entries without relying on result order or name
515 * matching.
516 */
517 appendStringInfo(&cmd,
518 "SELECT s.seqidx, has_sequence_privilege(c.oid, 'SELECT'),\n"
519 " ps.*, seq.seqtypid,\n"
520 " seq.seqstart, seq.seqincrement, seq.seqmin,\n"
521 " seq.seqmax, seq.seqcycle\n"
522 "FROM ( VALUES %s ) AS s (schname, seqname, seqidx)\n"
523 "JOIN pg_namespace n ON n.nspname = s.schname\n"
524 "JOIN pg_class c ON c.relnamespace = n.oid AND c.relname = s.seqname\n"
525 "JOIN pg_sequence seq ON seq.seqrelid = c.oid\n"
526 "JOIN LATERAL pg_get_sequence_data(seq.seqrelid) AS ps ON true\n",
527 seqstr.data);
528
529 res = walrcv_exec(conn, cmd.data, lengthof(seqRow), seqRow);
530 if (res->status != WALRCV_OK_TUPLES)
533 errmsg("could not fetch sequence information from the publisher: %s",
534 res->err));
535
537 while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
538 {
542 int seqidx;
543
545
547 {
548 ConfigReloadPending = false;
550 }
551
553 &seqinfo, &seqidx);
556 sequence_rel->rd_rel->relowner);
557
558 switch (sync_status)
559 {
560 case COPYSEQ_SUCCESS:
561 elog(DEBUG1,
562 "logical replication synchronization for subscription \"%s\", sequence \"%s.%s\" has finished",
563 MySubscription->name, seqinfo->nspname,
564 seqinfo->seqname);
566 break;
567 case COPYSEQ_MISMATCH:
568
569 /*
570 * Remember mismatched sequences in a long-lived memory
571 * context since these will be used after the transaction
572 * is committed.
573 */
576 seqidx);
579 break;
581
582 /*
583 * Remember sequences with insufficient privileges in a
584 * long-lived memory context since these will be used
585 * after the transaction is committed.
586 */
589 seqidx);
592 break;
594
595 /*
596 * Remember sequences for which the publisher lacks the
597 * privileges required by pg_get_sequence_data().
598 */
601 seqidx);
604 break;
605 case COPYSEQ_SKIPPED:
606
607 /*
608 * Concurrent removal of a sequence on the subscriber is
609 * treated as success, since the only viable action is to
610 * skip the corresponding sequence data. Missing sequences
611 * on the publisher are treated as ERROR.
612 */
613 if (seqinfo->found_on_pub)
614 {
615 ereport(LOG,
616 errmsg("skip synchronization of sequence \"%s.%s\" because it has been dropped concurrently",
617 seqinfo->nspname,
618 seqinfo->seqname));
620 }
621 break;
622 }
623
624 if (sequence_rel)
626 }
627
631 resetStringInfo(&cmd);
632
638
639 elog(DEBUG1,
640 "logical replication sequence synchronization for subscription \"%s\" - batch #%d = %d attempted, %d succeeded, %d mismatched, %d subscriber insufficient permission, %d publisher insufficient permission, %d missing from publisher, %d skipped",
645
646 /* Commit this batch, and prepare for next batch */
648
650 {
651 for (int idx = cur_batch_base_index; idx < cur_batch_base_index + batch_size; idx++)
652 {
655
656 /* If the sequence was not found on publisher, record it */
657 if (!seqinfo->found_on_pub)
659 }
660 }
661
662 /*
663 * cur_batch_base_index is not incremented sequentially because some
664 * sequences may be missing, and the number of fetched rows may not
665 * match the batch size.
666 */
667 cur_batch_base_index += batch_size;
668 }
669
670 /* Report mismatches, permission issues, or missing sequences */
673}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:263
MemoryContext ApplyContext
Definition worker.c:477
#define lengthof(array)
Definition c.h:932
int errcode(int sqlerrcode)
Definition elog.c:875
#define LOG
Definition elog.h:32
#define DEBUG1
Definition elog.h:31
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
void ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
const TupleTableSlotOps TTSOpsMinimalTuple
Definition execTuples.c:86
void ProcessConfigFile(GucContext context)
Definition guc-file.l:120
@ PGC_SIGHUP
Definition guc.h:75
volatile sig_atomic_t ConfigReloadPending
Definition interrupt.c:27
List * lappend_int(List *list, int datum)
Definition list.c:357
#define NoLock
Definition lockdefs.h:34
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
static char * errmsg
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
static void * list_nth(const List *list, int n)
Definition pg_list.h:331
char * quote_literal_cstr(const char *rawstr)
Definition quote.c:101
#define REMOTE_SEQ_COL_COUNT
static CopySeqResult get_and_validate_seq_info(TupleTableSlot *slot, Relation *sequence_rel, LogicalRepSequenceInfo **seqinfo, int *seqidx)
static List * seqinfos
#define MAX_SEQUENCES_SYNC_PER_BATCH
static void report_sequence_errors(List *mismatched_seqs_idx, List *sub_insuffperm_seqs_idx, List *pub_insuffperm_seqs_idx, List *missing_seqs_idx)
static CopySeqResult copy_sequence(LogicalRepSequenceInfo *seqinfo, Oid seqowner)
PGconn * conn
Definition streamutil.c:52
void resetStringInfo(StringInfo str)
Definition stringinfo.c:126
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Definition pg_list.h:54
Tuplestorestate * tuplestore
TupleDesc tupledesc
WalRcvExecStatus status
void table_close(Relation relation, LOCKMODE lockmode)
Definition table.c:126
bool tuplestore_gettupleslot(Tuplestorestate *state, bool forward, bool copy, TupleTableSlot *slot)
@ WALRCV_OK_TUPLES
static void walrcv_clear_result(WalRcvExecResult *walres)
#define walrcv_exec(conn, exec, nRetTypes, retTypes)
void StartTransactionCommand(void)
Definition xact.c:3112
void CommitTransactionCommand(void)
Definition xact.c:3210

References appendStringInfo(), appendStringInfoString(), ApplyContext, CHECK_FOR_INTERRUPTS, CommitTransactionCommand(), ConfigReloadPending, conn, copy_sequence(), COPYSEQ_MISMATCH, COPYSEQ_PUBLISHER_INSUFFICIENT_PERM, COPYSEQ_SKIPPED, COPYSEQ_SUBSCRIBER_INSUFFICIENT_PERM, COPYSEQ_SUCCESS, StringInfoData::data, DEBUG1, elog, ereport, WalRcvExecResult::err, errcode(), errmsg, ERROR, ExecDropSingleTupleTableSlot(), fb(), get_and_validate_seq_info(), idx(), initStringInfo(), lappend_int(), lengthof, list_length(), list_nth(), LOG, MakeSingleTupleTableSlot(), MAX_SEQUENCES_SYNC_PER_BATCH, MemoryContextSwitchTo(), MySubscription, Subscription::name, NIL, NoLock, PGC_SIGHUP, ProcessConfigFile(), quote_literal_cstr(), REMOTE_SEQ_COL_COUNT, report_sequence_errors(), resetStringInfo(), seqinfos, StartTransactionCommand(), WalRcvExecResult::status, table_close(), TTSOpsMinimalTuple, WalRcvExecResult::tupledesc, WalRcvExecResult::tuplestore, tuplestore_gettupleslot(), walrcv_clear_result(), walrcv_exec, and WALRCV_OK_TUPLES.

Referenced by LogicalRepSyncSequences().

◆ get_and_validate_seq_info()

static CopySeqResult get_and_validate_seq_info ( TupleTableSlot slot,
Relation sequence_rel,
LogicalRepSequenceInfo **  seqinfo,
int seqidx 
)
static

Definition at line 267 of file sequencesync.c.

269{
270 bool isnull;
271 int col = 0;
272 Datum datum;
279 bool remote_cycle;
284
285 *seqidx = DatumGetInt32(slot_getattr(slot, ++col, &isnull));
286 Assert(!isnull);
287
288 /* Identify the corresponding local sequence for the given index. */
291
292 /*
293 * The remote sequence state can be NULL if the publisher lacks the
294 * required privileges or if the sequence was dropped concurrently after
295 * it was identified in the catalog snapshot (see pg_get_sequence_data()).
296 */
298 Assert(!isnull);
299
300 datum = slot_getattr(slot, ++col, &isnull);
301 if (isnull)
304
305 seqinfo_local->last_value = DatumGetInt64(datum);
306
307 seqinfo_local->is_called = DatumGetBool(slot_getattr(slot, ++col, &isnull));
308 Assert(!isnull);
309
310 seqinfo_local->page_lsn = DatumGetLSN(slot_getattr(slot, ++col, &isnull));
311 Assert(!isnull);
312
313 remote_typid = DatumGetObjectId(slot_getattr(slot, ++col, &isnull));
314 Assert(!isnull);
315
316 remote_start = DatumGetInt64(slot_getattr(slot, ++col, &isnull));
317 Assert(!isnull);
318
319 remote_increment = DatumGetInt64(slot_getattr(slot, ++col, &isnull));
320 Assert(!isnull);
321
322 remote_min = DatumGetInt64(slot_getattr(slot, ++col, &isnull));
323 Assert(!isnull);
324
325 remote_max = DatumGetInt64(slot_getattr(slot, ++col, &isnull));
326 Assert(!isnull);
327
328 remote_cycle = DatumGetBool(slot_getattr(slot, ++col, &isnull));
329 Assert(!isnull);
330
331 /* Sanity check */
333
334 seqinfo_local->found_on_pub = true;
335
337
338 /* Sequence was concurrently dropped? */
339 if (!*sequence_rel)
340 return COPYSEQ_SKIPPED;
341
343
344 /* Sequence was concurrently dropped? */
345 if (!HeapTupleIsValid(tup))
346 elog(ERROR, "cache lookup failed for sequence %u",
347 seqinfo_local->localrelid);
348
350
351 /* Sequence parameters for remote/local are the same? */
352 if (local_seq->seqtypid != remote_typid ||
353 local_seq->seqstart != remote_start ||
354 local_seq->seqincrement != remote_increment ||
355 local_seq->seqmin != remote_min ||
356 local_seq->seqmax != remote_max ||
357 local_seq->seqcycle != remote_cycle)
359
360 /* Sequence was concurrently renamed? */
361 if (strcmp(seqinfo_local->nspname,
365
367 return result;
368}
#define Assert(condition)
Definition c.h:1002
int64_t int64
Definition c.h:680
uint32 result
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
#define RowExclusiveLock
Definition lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition lsyscache.c:3682
static XLogRecPtr DatumGetLSN(Datum X)
Definition pg_lsn.h:25
END_CATALOG_STRUCT typedef FormData_pg_sequence * Form_pg_sequence
Definition pg_sequence.h:44
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static int64 DatumGetInt64(Datum X)
Definition postgres.h:416
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static int32 DatumGetInt32(Datum X)
Definition postgres.h:202
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationGetNamespace(relation)
Definition rel.h:557
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221
Relation try_table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:60
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition tuptable.h:417

References Assert, COPYSEQ_MISMATCH, COPYSEQ_PUBLISHER_INSUFFICIENT_PERM, COPYSEQ_SKIPPED, COPYSEQ_SUCCESS, DatumGetBool(), DatumGetInt32(), DatumGetInt64(), DatumGetLSN(), DatumGetObjectId(), elog, ERROR, fb(), Form_pg_sequence, get_namespace_name(), GETSTRUCT(), HeapTupleIsValid, list_nth(), ObjectIdGetDatum(), RelationGetNamespace, RelationGetRelationName, ReleaseSysCache(), REMOTE_SEQ_COL_COUNT, result, RowExclusiveLock, SearchSysCache1(), seqinfos, slot_getattr(), and try_table_open().

Referenced by copy_sequences().

◆ get_sequences_string()

static void get_sequences_string ( List seqindexes,
StringInfo  buf 
)
static

Definition at line 149 of file sequencesync.c.

150{
153 {
156
157 if (buf->len > 0)
159
160 appendStringInfo(buf, "\"%s.%s\"", seqinfo->nspname, seqinfo->seqname);
161 }
162}
#define foreach_int(var, lst)
Definition pg_list.h:502
static char buf[DEFAULT_XLOG_SEG_SIZE]

References appendStringInfo(), appendStringInfoString(), buf, fb(), foreach_int, list_nth(), resetStringInfo(), and seqinfos.

Referenced by report_sequence_errors().

◆ LogicalRepSyncSequences()

static void LogicalRepSyncSequences ( void  )
static

Definition at line 680 of file sequencesync.c.

681{
682 char *err;
684 Relation rel;
686 ScanKeyData skey[2];
687 SysScanDesc scan;
690
692
694
695 ScanKeyInit(&skey[0],
698 ObjectIdGetDatum(subid));
699
700 ScanKeyInit(&skey[1],
704
705 scan = systable_beginscan(rel, InvalidOid, false,
706 NULL, 2, skey);
707 while (HeapTupleIsValid(tup = systable_getnext(scan)))
708 {
713
715
717
719
720 /* Skip if sequence was dropped concurrently */
721 if (!sequence_rel)
722 continue;
723
724 /* Skip if the relation is not a sequence */
725 if (sequence_rel->rd_rel->relkind != RELKIND_SEQUENCE)
726 {
728 continue;
729 }
730
731 /*
732 * Worker needs to process sequences across transaction boundary, so
733 * allocate them under long-lived context.
734 */
736
738 seq->localrelid = subrel->srrelid;
742
744
746 }
747
748 /* Cleanup */
749 systable_endscan(scan);
751
753
754 /*
755 * Exit early if no catalog entries found, likely due to concurrent drops.
756 */
757 if (!seqinfos)
758 return;
759
760 /* Is the use of a password mandatory? */
763
765 appendStringInfo(&app_name, "pg_%u_sequence_sync_" UINT64_FORMAT,
767
768 /*
769 * Establish the connection to the publisher for sequence synchronization.
770 */
774 app_name.data, &err);
778 errmsg("sequencesync worker for subscription \"%s\" could not connect to the publisher: %s",
780
781 pfree(app_name.data);
782
784}
WalReceiverConn * LogRepWorkerWalRcvConn
Definition worker.c:482
#define UINT64_FORMAT
Definition c.h:694
void err(int eval, const char *fmt,...)
Definition err.c:43
#define palloc0_object(type)
Definition fe_memutils.h:90
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition genam.c:388
LogicalRepWorker * MyLogicalRepWorker
Definition launcher.c:58
List * lappend(List *list, void *datum)
Definition list.c:339
#define AccessShareLock
Definition lockdefs.h:36
char * pstrdup(const char *in)
Definition mcxt.c:1910
void pfree(void *pointer)
Definition mcxt.c:1619
END_CATALOG_STRUCT typedef FormData_pg_subscription_rel * Form_pg_subscription_rel
static Datum CharGetDatum(char X)
Definition postgres.h:132
#define InvalidOid
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
static void copy_sequences(WalReceiverConn *conn)
#define BTEqualStrategyNumber
Definition stratnum.h:31
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition table.c:40
#define walrcv_connect(conninfo, replication, logical, must_use_password, appname, err)
uint64 GetSystemIdentifier(void)
Definition xlog.c:4642

References AccessShareLock, appendStringInfo(), ApplyContext, BTEqualStrategyNumber, CharGetDatum(), CHECK_FOR_INTERRUPTS, CommitTransactionCommand(), Subscription::conninfo, copy_sequences(), ereport, err(), errcode(), errmsg, ERROR, fb(), Form_pg_subscription_rel, get_namespace_name(), GETSTRUCT(), GetSystemIdentifier(), HeapTupleIsValid, initStringInfo(), InvalidOid, lappend(), LogRepWorkerWalRcvConn, MemoryContextSwitchTo(), MyLogicalRepWorker, MySubscription, Subscription::name, NoLock, ObjectIdGetDatum(), Subscription::oid, Subscription::ownersuperuser, palloc0_object, Subscription::passwordrequired, pfree(), pstrdup(), RelationGetNamespace, RelationGetRelationName, RowExclusiveLock, ScanKeyInit(), seqinfos, StartTransactionCommand(), LogicalRepWorker::subid, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), try_table_open(), UINT64_FORMAT, and walrcv_connect.

Referenced by start_sequence_sync().

◆ ProcessSequencesForSync()

void ProcessSequencesForSync ( void  )

Definition at line 97 of file sequencesync.c.

98{
100 int nsyncworkers;
102 bool started_tx;
103
105
106 if (started_tx)
107 {
109 pgstat_report_stat(true);
110 }
111
113 return;
114
116
117 /* Check if there is a sequencesync worker already running? */
120 InvalidOid, true);
122 {
124 return;
125 }
126
127 /*
128 * Count running sync workers for this subscription, while we have the
129 * lock.
130 */
133
134 /*
135 * It is okay to read/update last_seqsync_start_time here in apply worker
136 * as we have already ensured that sync worker doesn't exist.
137 */
140}
LogicalRepWorker * logicalrep_worker_find(LogicalRepWorkerType wtype, Oid subid, Oid relid, bool only_running)
Definition launcher.c:268
int logicalrep_sync_worker_count(Oid subid)
Definition launcher.c:937
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_SHARED
Definition lwlock.h:105
long pgstat_report_stat(bool force)
Definition pgstat.c:722
TimestampTz last_seqsync_start_time
void launch_sync_worker(LogicalRepWorkerType wtype, int nsyncworkers, Oid relid, TimestampTz *last_start_time)
Definition syncutils.c:118
void FetchRelationStates(bool *has_pending_subtables, bool *has_pending_subsequences, bool *started_tx)
Definition syncutils.c:203
@ WORKERTYPE_SEQUENCESYNC

References CommitTransactionCommand(), fb(), FetchRelationStates(), InvalidOid, LogicalRepWorker::last_seqsync_start_time, launch_sync_worker(), logicalrep_sync_worker_count(), logicalrep_worker_find(), LW_SHARED, LWLockAcquire(), LWLockRelease(), MyLogicalRepWorker, pgstat_report_stat(), LogicalRepWorker::subid, and WORKERTYPE_SEQUENCESYNC.

Referenced by ProcessSyncingRelations().

◆ report_sequence_errors()

static void report_sequence_errors ( List mismatched_seqs_idx,
List sub_insuffperm_seqs_idx,
List pub_insuffperm_seqs_idx,
List missing_seqs_idx 
)
static

Definition at line 176 of file sequencesync.c.

180{
182
183 /* Quick exit if there are no errors to report */
186 return;
187
189
191 {
195 errmsg_plural("mismatched or renamed sequence on subscriber (%s)",
196 "mismatched or renamed sequences on subscriber (%s)",
198 seqstr.data));
199 }
200
202 {
204
205 /*
206 * With run_as_owner enabled, sequence synchronization runs as the
207 * subscription owner, so a missing UPDATE privilege should be granted
208 * to that role. Otherwise, the worker switches to the sequence owner
209 * before checking privileges, so no useful GRANT hint can be
210 * provided.
211 */
214 errmsg_plural("insufficient privileges on subscriber sequence (%s)",
215 "insufficient privileges on subscriber sequences (%s)",
217 seqstr.data),
219 errhint_plural("Grant UPDATE on the sequence to the subscription "
220 "owner on the subscriber.",
221 "Grant UPDATE on the sequences to the subscription "
222 "owner on the subscriber.",
224 }
225
227 {
231 errmsg_plural("insufficient privileges on publisher sequence (%s)",
232 "insufficient privileges on publisher sequences (%s)",
234 seqstr.data),
235 errhint_plural("Grant SELECT on the sequence to the role used for "
236 "the replication connection on the publisher.",
237 "Grant SELECT on the sequences to the role used for "
238 "the replication connection on the publisher.",
240 }
241
243 {
247 errmsg_plural("missing sequence on publisher (%s)",
248 "missing sequences on publisher (%s)",
250 seqstr.data));
251 }
252
255 errmsg("logical replication sequence synchronization failed for subscription \"%s\"",
257}
int int int errhint_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
int int int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...) pg_attribute_printf(1
static void get_sequences_string(List *seqindexes, StringInfo buf)

References ereport, errcode(), errhint_plural(), errmsg, errmsg_plural(), ERROR, fb(), get_sequences_string(), initStringInfo(), list_length(), MySubscription, Subscription::name, Subscription::runasowner, and WARNING.

Referenced by copy_sequences().

◆ SequenceSyncWorkerMain()

void SequenceSyncWorkerMain ( Datum  main_arg)

Definition at line 825 of file sequencesync.c.

826{
828
830
832
834}
void SetupApplyOrSyncWorker(int worker_slot)
Definition worker.c:5963
static void start_sequence_sync(void)
pg_noreturn void FinishSyncWorker(void)
Definition syncutils.c:50

References DatumGetInt32(), fb(), FinishSyncWorker(), SetupApplyOrSyncWorker(), and start_sequence_sync().

◆ start_sequence_sync()

static void start_sequence_sync ( void  )
static

Definition at line 794 of file sequencesync.c.

795{
797
798 PG_TRY();
799 {
800 /* Call initial sync. */
802 }
803 PG_CATCH();
804 {
807 else
808 {
809 /*
810 * Report the worker failed during sequence synchronization. Abort
811 * the current transaction so that the stats message is sent in an
812 * idle state.
813 */
816
817 PG_RE_THROW();
818 }
819 }
820 PG_END_TRY();
821}
void DisableSubscriptionAndExit(void)
Definition worker.c:6023
#define PG_RE_THROW()
Definition elog.h:407
#define PG_TRY(...)
Definition elog.h:374
#define PG_END_TRY(...)
Definition elog.h:399
#define PG_CATCH(...)
Definition elog.h:384
void pgstat_report_subscription_error(Oid subid)
static void LogicalRepSyncSequences(void)
static bool am_sequencesync_worker(void)
void AbortOutOfAnyTransaction(void)
Definition xact.c:4916

References AbortOutOfAnyTransaction(), am_sequencesync_worker(), Assert, Subscription::disableonerr, DisableSubscriptionAndExit(), LogicalRepSyncSequences(), MySubscription, Subscription::oid, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, and pgstat_report_subscription_error().

Referenced by SequenceSyncWorkerMain().

Variable Documentation

◆ seqinfos

List* seqinfos = NIL
static