Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d3e8368

Browse files
author
Amit Kapila
committed
Add the additional information to the logical replication worker errcontext.
This commits adds both the finish LSN (commit_lsn in case transaction got committed, prepare_lsn in case of a prepared transaction, etc.) and replication origin name to the existing error context message. This will help users in specifying the origin name and transaction finish LSN to pg_replication_origin_advance() SQL function to skip a particular transaction. Author: Masahiko Sawada Reviewed-by: Takamichi Osumi, Euler Taveira, and Amit Kapila Discussion: https://postgr.es/m/CAD21AoBarBf2oTF71ig2g_o=3Z_Dt6_sOpMQma1kFgbnA5OZ_w@mail.gmail.com
1 parent 4228cab commit d3e8368

File tree

2 files changed

+75
-23
lines changed

2 files changed

+75
-23
lines changed

doc/src/sgml/logical-replication.sgml

+19-4
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,26 @@
352352
<para>
353353
The resolution can be done either by changing data or permissions on the subscriber so
354354
that it does not conflict with the incoming change or by skipping the
355-
transaction that conflicts with the existing data. The transaction can be
356-
skipped by calling the <link linkend="pg-replication-origin-advance">
355+
transaction that conflicts with the existing data. When a conflict produces
356+
an error, the replication won't proceed, and the logical replication worker will
357+
emit the following kind of message to the subscriber's server log:
358+
<screen>
359+
ERROR: duplicate key value violates unique constraint "test_pkey"
360+
DETAIL: Key (c)=(1) already exists.
361+
CONTEXT: processing remote data for replication origin "pg_16395" during "INSERT" for replication target relation "public.test" in transaction 725 finished at 0/14C0378
362+
</screen>
363+
The LSN of the transaction that contains the change violating the constraint and
364+
the replication origin name can be found from the server log (LSN 0/14C0378 and
365+
replication origin <literal>pg_16395</literal> in the above case). To skip the
366+
transaction, the subscription needs to be disabled temporarily by
367+
<command>ALTER SUBSCRIPTION ... DISABLE</command> first. Then, the transaction
368+
can be skipped by calling the
369+
<link linkend="pg-replication-origin-advance">
357370
<function>pg_replication_origin_advance()</function></link> function with
358-
a <parameter>node_name</parameter> corresponding to the subscription name,
359-
and a position. The current position of origins can be seen in the
371+
the <parameter>node_name</parameter> (i.e., <literal>pg_16395</literal>) and the
372+
next LSN of the transaction's LSN (i.e., LSN 0/14C0379). After that the replication
373+
can be resumed by <command>ALTER SUBSCRIPTION ... ENABLE</command>. The current
374+
position of origins can be seen in the
360375
<link linkend="view-pg-replication-origin-status">
361376
<structname>pg_replication_origin_status</structname></link> system view.
362377
</para>

src/backend/replication/logical/worker.c

+56-19
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ typedef struct ApplyErrorCallbackArg
226226
/* Remote node information */
227227
int remote_attnum; /* -1 if invalid */
228228
TransactionId remote_xid;
229+
XLogRecPtr finish_lsn;
230+
char *origin_name;
229231
} ApplyErrorCallbackArg;
230232

231233
static ApplyErrorCallbackArg apply_error_callback_arg =
@@ -234,6 +236,8 @@ static ApplyErrorCallbackArg apply_error_callback_arg =
234236
.rel = NULL,
235237
.remote_attnum = -1,
236238
.remote_xid = InvalidTransactionId,
239+
.finish_lsn = InvalidXLogRecPtr,
240+
.origin_name = NULL,
237241
};
238242

239243
static MemoryContext ApplyMessageContext = NULL;
@@ -332,7 +336,7 @@ static void apply_spooled_messages(TransactionId xid, XLogRecPtr lsn);
332336

333337
/* Functions for apply error callback */
334338
static void apply_error_callback(void *arg);
335-
static inline void set_apply_error_context_xact(TransactionId xid);
339+
static inline void set_apply_error_context_xact(TransactionId xid, XLogRecPtr lsn);
336340
static inline void reset_apply_error_context_info(void);
337341

338342
/*
@@ -785,7 +789,7 @@ apply_handle_begin(StringInfo s)
785789
LogicalRepBeginData begin_data;
786790

787791
logicalrep_read_begin(s, &begin_data);
788-
set_apply_error_context_xact(begin_data.xid);
792+
set_apply_error_context_xact(begin_data.xid, begin_data.final_lsn);
789793

790794
remote_final_lsn = begin_data.final_lsn;
791795

@@ -837,7 +841,7 @@ apply_handle_begin_prepare(StringInfo s)
837841
errmsg_internal("tablesync worker received a BEGIN PREPARE message")));
838842

839843
logicalrep_read_begin_prepare(s, &begin_data);
840-
set_apply_error_context_xact(begin_data.xid);
844+
set_apply_error_context_xact(begin_data.xid, begin_data.prepare_lsn);
841845

842846
remote_final_lsn = begin_data.prepare_lsn;
843847

@@ -936,7 +940,7 @@ apply_handle_commit_prepared(StringInfo s)
936940
char gid[GIDSIZE];
937941

938942
logicalrep_read_commit_prepared(s, &prepare_data);
939-
set_apply_error_context_xact(prepare_data.xid);
943+
set_apply_error_context_xact(prepare_data.xid, prepare_data.commit_lsn);
940944

941945
/* Compute GID for two_phase transactions. */
942946
TwoPhaseTransactionGid(MySubscription->oid, prepare_data.xid,
@@ -977,7 +981,7 @@ apply_handle_rollback_prepared(StringInfo s)
977981
char gid[GIDSIZE];
978982

979983
logicalrep_read_rollback_prepared(s, &rollback_data);
980-
set_apply_error_context_xact(rollback_data.xid);
984+
set_apply_error_context_xact(rollback_data.xid, rollback_data.rollback_end_lsn);
981985

982986
/* Compute GID for two_phase transactions. */
983987
TwoPhaseTransactionGid(MySubscription->oid, rollback_data.xid,
@@ -1042,7 +1046,7 @@ apply_handle_stream_prepare(StringInfo s)
10421046
errmsg_internal("tablesync worker received a STREAM PREPARE message")));
10431047

10441048
logicalrep_read_stream_prepare(s, &prepare_data);
1045-
set_apply_error_context_xact(prepare_data.xid);
1049+
set_apply_error_context_xact(prepare_data.xid, prepare_data.prepare_lsn);
10461050

10471051
elog(DEBUG1, "received prepare for streamed transaction %u", prepare_data.xid);
10481052

@@ -1124,7 +1128,7 @@ apply_handle_stream_start(StringInfo s)
11241128
(errcode(ERRCODE_PROTOCOL_VIOLATION),
11251129
errmsg_internal("invalid transaction ID in streamed replication transaction")));
11261130

1127-
set_apply_error_context_xact(stream_xid);
1131+
set_apply_error_context_xact(stream_xid, InvalidXLogRecPtr);
11281132

11291133
/*
11301134
* Initialize the worker's stream_fileset if we haven't yet. This will be
@@ -1213,7 +1217,7 @@ apply_handle_stream_abort(StringInfo s)
12131217
*/
12141218
if (xid == subxid)
12151219
{
1216-
set_apply_error_context_xact(xid);
1220+
set_apply_error_context_xact(xid, InvalidXLogRecPtr);
12171221
stream_cleanup_files(MyLogicalRepWorker->subid, xid);
12181222
}
12191223
else
@@ -1239,7 +1243,7 @@ apply_handle_stream_abort(StringInfo s)
12391243
bool found = false;
12401244
char path[MAXPGPATH];
12411245

1242-
set_apply_error_context_xact(subxid);
1246+
set_apply_error_context_xact(subxid, InvalidXLogRecPtr);
12431247

12441248
subidx = -1;
12451249
begin_replication_step();
@@ -1424,7 +1428,7 @@ apply_handle_stream_commit(StringInfo s)
14241428
errmsg_internal("STREAM COMMIT message without STREAM STOP")));
14251429

14261430
xid = logicalrep_read_stream_commit(s, &commit_data);
1427-
set_apply_error_context_xact(xid);
1431+
set_apply_error_context_xact(xid, commit_data.commit_lsn);
14281432

14291433
elog(DEBUG1, "received commit for streamed transaction %u", xid);
14301434

@@ -3499,6 +3503,17 @@ ApplyWorkerMain(Datum main_arg)
34993503
myslotname = MemoryContextStrdup(ApplyContext, syncslotname);
35003504

35013505
pfree(syncslotname);
3506+
3507+
/*
3508+
* Allocate the origin name in long-lived context for error context
3509+
* message.
3510+
*/
3511+
ReplicationOriginNameForTablesync(MySubscription->oid,
3512+
MyLogicalRepWorker->relid,
3513+
originname,
3514+
sizeof(originname));
3515+
apply_error_callback_arg.origin_name = MemoryContextStrdup(ApplyContext,
3516+
originname);
35023517
}
35033518
else
35043519
{
@@ -3542,6 +3557,13 @@ ApplyWorkerMain(Datum main_arg)
35423557
* does some initializations on the upstream so let's still call it.
35433558
*/
35443559
(void) walrcv_identify_system(LogRepWorkerWalRcvConn, &startpointTLI);
3560+
3561+
/*
3562+
* Allocate the origin name in long-lived context for error context
3563+
* message.
3564+
*/
3565+
apply_error_callback_arg.origin_name = MemoryContextStrdup(ApplyContext,
3566+
originname);
35453567
}
35463568

35473569
/*
@@ -3651,36 +3673,51 @@ apply_error_callback(void *arg)
36513673
if (apply_error_callback_arg.command == 0)
36523674
return;
36533675

3676+
Assert(errarg->origin_name);
3677+
36543678
if (errarg->rel == NULL)
36553679
{
36563680
if (!TransactionIdIsValid(errarg->remote_xid))
3657-
errcontext("processing remote data during \"%s\"",
3681+
errcontext("processing remote data for replication origin \"%s\" during \"%s\"",
3682+
errarg->origin_name,
36583683
logicalrep_message_type(errarg->command));
3659-
else
3660-
errcontext("processing remote data during \"%s\" in transaction %u",
3684+
else if (XLogRecPtrIsInvalid(errarg->finish_lsn))
3685+
errcontext("processing remote data for replication origin \"%s\" during \"%s\" in transaction %u",
3686+
errarg->origin_name,
36613687
logicalrep_message_type(errarg->command),
36623688
errarg->remote_xid);
3689+
else
3690+
errcontext("processing remote data for replication origin \"%s\" during \"%s\" in transaction %u finished at %X/%X",
3691+
errarg->origin_name,
3692+
logicalrep_message_type(errarg->command),
3693+
errarg->remote_xid,
3694+
LSN_FORMAT_ARGS(errarg->finish_lsn));
36633695
}
36643696
else if (errarg->remote_attnum < 0)
3665-
errcontext("processing remote data during \"%s\" for replication target relation \"%s.%s\" in transaction %u",
3697+
errcontext("processing remote data for replication origin \"%s\" during \"%s\" for replication target relation \"%s.%s\" in transaction %u finished at %X/%X",
3698+
errarg->origin_name,
36663699
logicalrep_message_type(errarg->command),
36673700
errarg->rel->remoterel.nspname,
36683701
errarg->rel->remoterel.relname,
3669-
errarg->remote_xid);
3702+
errarg->remote_xid,
3703+
LSN_FORMAT_ARGS(errarg->finish_lsn));
36703704
else
3671-
errcontext("processing remote data during \"%s\" for replication target relation \"%s.%s\" column \"%s\" in transaction %u",
3705+
errcontext("processing remote data for replication origin \"%s\" during \"%s\" for replication target relation \"%s.%s\" column \"%s\" in transaction %u finished at %X/%X",
3706+
errarg->origin_name,
36723707
logicalrep_message_type(errarg->command),
36733708
errarg->rel->remoterel.nspname,
36743709
errarg->rel->remoterel.relname,
36753710
errarg->rel->remoterel.attnames[errarg->remote_attnum],
3676-
errarg->remote_xid);
3711+
errarg->remote_xid,
3712+
LSN_FORMAT_ARGS(errarg->finish_lsn));
36773713
}
36783714

36793715
/* Set transaction information of apply error callback */
36803716
static inline void
3681-
set_apply_error_context_xact(TransactionId xid)
3717+
set_apply_error_context_xact(TransactionId xid, XLogRecPtr lsn)
36823718
{
36833719
apply_error_callback_arg.remote_xid = xid;
3720+
apply_error_callback_arg.finish_lsn = lsn;
36843721
}
36853722

36863723
/* Reset all information of apply error callback */
@@ -3690,5 +3727,5 @@ reset_apply_error_context_info(void)
36903727
apply_error_callback_arg.command = 0;
36913728
apply_error_callback_arg.rel = NULL;
36923729
apply_error_callback_arg.remote_attnum = -1;
3693-
set_apply_error_context_xact(InvalidTransactionId);
3730+
set_apply_error_context_xact(InvalidTransactionId, InvalidXLogRecPtr);
36943731
}

0 commit comments

Comments
 (0)