1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Add error context for sequence synchronization.

An unhandled ERROR while synchronizing a sequence (for example, when
SwitchToUntrustedUser() fails because the subscription owner cannot SET
ROLE to the sequence owner) makes the sequencesync worker exit and be
restarted, repeatedly, until the user resolves the problem, as with the
apply worker. The error message does not identify the sequence or
subscription responsible.

Add an error context callback around per-sequence validation and
synchronization in copy_sequences() so that such errors report the
schema-qualified sequence name and subscription name in CONTEXT.

Reported-by: Zsolt Parragi <zsolt.parragi@percona.com>
Author: Zhijie Hou <houzhijie22@gmail.com>
Reviewed-by: Ajin Cherian <itsajin@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: vignesh C <vignesh21@gmail.com>
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Discussion: https://postgr.es/m/CAN4CZFMGiyksxVD1M7cc7_5E+evfi51xmDxw4uqdmvoeH53Ugw@mail.gmail.com
Backpatch-through: 19
This commit is contained in:
Amit Kapila
2026-10-22 10:38:34 +05:30
parent a19c3f36b3
commit 215af457ae
2 changed files with 81 additions and 1 deletions

View File

@@ -163,6 +163,22 @@ get_sequences_string(List *seqindexes, StringInfo buf)
}
}
/*
* Error callback to give more context info about the sequence being
* synchronized.
*/
static void
sequence_sync_error_callback(void *arg)
{
LogicalRepSequenceInfo *seqinfo = *(LogicalRepSequenceInfo **) arg;
if (seqinfo == NULL)
return;
errcontext("synchronizing sequence \"%s.%s\" for subscription \"%s\"",
seqinfo->nspname, seqinfo->seqname, MySubscription->name);
}
/*
* report_sequence_errors
*
@@ -621,9 +637,10 @@ copy_sequences(WalReceiverConn *conn)
while (tuplestore_gettupleslot(res->tuplestore, true, false, slot))
{
CopySeqResult sync_status;
LogicalRepSequenceInfo *seqinfo;
LogicalRepSequenceInfo *seqinfo = NULL;
Relation sequence_rel = NULL;
int seqidx;
ErrorContextCallback errcallback;
CHECK_FOR_INTERRUPTS();
@@ -633,12 +650,25 @@ copy_sequences(WalReceiverConn *conn)
ProcessConfigFile(PGC_SIGHUP);
}
/*
* Set up callback to identify the sequence in error messages.
* seqinfo will be filled once get_and_validate_seq_info()
* resolves the sequence index.
*/
errcallback.callback = sequence_sync_error_callback;
errcallback.arg = &seqinfo;
errcallback.previous = error_context_stack;
error_context_stack = &errcallback;
sync_status = get_and_validate_seq_info(slot, &sequence_rel,
&seqinfo, &seqidx);
if (sync_status == COPYSEQ_SUCCESS)
sync_status = copy_sequence(seqinfo,
sequence_rel->rd_rel->relowner);
/* Pop the error context stack */
error_context_stack = errcallback.previous;
switch (sync_status)
{
case COPYSEQ_SUCCESS:

View File

@@ -382,4 +382,54 @@ $node_subscriber->wait_for_log(
qr/WARNING: ( [A-Z0-9]+:)? missing sequence on publisher \("public.regress_s2"\)/,
$log_offset);
# Remove the dropped sequence (regress_s2) from the subscription so that the
# apply worker does not keep starting the sequencesync worker for the missing
# sequence, which would pollute the logs and delay the next worker launch.
$node_subscriber->safe_psql('postgres',
"ALTER SUBSCRIPTION regress_seq_sub REFRESH PUBLICATION WITH (copy_data = false)"
);
##########
# Ensure that an error raised while synchronizing a sequence includes the
# sequence name in the error context.
##########
# Disable the subscription and wait for its workers to stop before changing its
# connection and owner.
$node_subscriber->safe_psql('postgres',
"ALTER SUBSCRIPTION regress_seq_sub DISABLE");
$node_subscriber->poll_query_until(
'postgres', qq(
SELECT count(1) = 0 FROM pg_stat_subscription
WHERE subname = 'regress_seq_sub' AND pid IS NOT NULL;
)) or die "Timed out while waiting for subscription workers to stop";
# Change the subscription owner to regress_seq_sub_owner, and make regress_s4
# owned by a separate role (regress_seq_other) that regress_seq_sub_owner
# cannot SET ROLE to. With run_as_owner = false (the default), synchronizing
# regress_s4 will fail when switching to its owner.
$node_subscriber->safe_psql(
'postgres', qq(
ALTER SUBSCRIPTION regress_seq_sub CONNECTION '$publisher_connstr';
ALTER SUBSCRIPTION regress_seq_sub SET (password_required = false);
CREATE ROLE regress_seq_sub_owner LOGIN;
CREATE ROLE regress_seq_other;
ALTER SEQUENCE regress_s1 OWNER TO regress_seq_sub_owner;
ALTER SEQUENCE regress_s3 OWNER TO regress_seq_sub_owner;
ALTER SEQUENCE "regress'quote" OWNER TO regress_seq_sub_owner;
ALTER SEQUENCE regress_s4 OWNER TO regress_seq_other;
ALTER SUBSCRIPTION regress_seq_sub OWNER TO regress_seq_sub_owner;
ALTER SUBSCRIPTION regress_seq_sub ENABLE;
));
$log_offset = -s $node_subscriber->logfile;
$node_subscriber->safe_psql('postgres',
"ALTER SUBSCRIPTION regress_seq_sub REFRESH SEQUENCES");
# Verify that the SET ROLE error reports the failing sequence in CONTEXT.
$node_subscriber->wait_for_log(
qr/ERROR: ( [A-Z0-9]+:)? role "regress_seq_sub_owner" cannot SET ROLE to "regress_seq_other"\n.*CONTEXT: synchronizing sequence "public\.regress_s4" for subscription "regress_seq_sub"/,
$log_offset);
done_testing();