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:
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user