@@ -118,10 +118,14 @@ pg_create_physical_replication_slot(PG_FUNCTION_ARGS)
118
118
* Helper function for creating a new logical replication slot with
119
119
* given arguments. Note that this function doesn't release the created
120
120
* slot.
121
+ *
122
+ * When find_startpoint is false, the slot's confirmed_flush is not set; it's
123
+ * caller's responsibility to ensure it's set to something sensible.
121
124
*/
122
125
static void
123
126
create_logical_replication_slot (char * name , char * plugin ,
124
- bool temporary , XLogRecPtr restart_lsn )
127
+ bool temporary , XLogRecPtr restart_lsn ,
128
+ bool find_startpoint )
125
129
{
126
130
LogicalDecodingContext * ctx = NULL ;
127
131
@@ -139,16 +143,24 @@ create_logical_replication_slot(char *name, char *plugin,
139
143
temporary ? RS_TEMPORARY : RS_EPHEMERAL );
140
144
141
145
/*
142
- * Create logical decoding context, to build the initial snapshot.
146
+ * Create logical decoding context to find start point or, if we don't
147
+ * need it, to 1) bump slot's restart_lsn and xmin 2) check plugin sanity.
148
+ *
149
+ * Note: when !find_startpoint this is still important, because it's at
150
+ * this point that the output plugin is validated.
143
151
*/
144
152
ctx = CreateInitDecodingContext (plugin , NIL ,
145
- false, /* do not build snapshot */
153
+ false, /* just catalogs is OK */
146
154
restart_lsn ,
147
155
logical_read_local_xlog_page , NULL , NULL ,
148
156
NULL );
149
157
150
- /* build initial snapshot, might take a while */
151
- DecodingContextFindStartpoint (ctx );
158
+ /*
159
+ * If caller needs us to determine the decoding start point, do so now.
160
+ * This might take a while.
161
+ */
162
+ if (find_startpoint )
163
+ DecodingContextFindStartpoint (ctx );
152
164
153
165
/* don't need the decoding context anymore */
154
166
FreeDecodingContext (ctx );
@@ -179,7 +191,8 @@ pg_create_logical_replication_slot(PG_FUNCTION_ARGS)
179
191
create_logical_replication_slot (NameStr (* name ),
180
192
NameStr (* plugin ),
181
193
temporary ,
182
- InvalidXLogRecPtr );
194
+ InvalidXLogRecPtr ,
195
+ true);
183
196
184
197
values [0 ] = NameGetDatum (& MyReplicationSlot -> data .name );
185
198
values [1 ] = LSNGetDatum (MyReplicationSlot -> data .confirmed_flush );
@@ -683,10 +696,18 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
683
696
684
697
/* Create new slot and acquire it */
685
698
if (logical_slot )
699
+ {
700
+ /*
701
+ * We must not try to read WAL, since we haven't reserved it yet --
702
+ * hence pass find_startpoint false. confirmed_flush will be set
703
+ * below, by copying from the source slot.
704
+ */
686
705
create_logical_replication_slot (NameStr (* dst_name ),
687
706
plugin ,
688
707
temporary ,
689
- src_restart_lsn );
708
+ src_restart_lsn ,
709
+ false);
710
+ }
690
711
else
691
712
create_physical_replication_slot (NameStr (* dst_name ),
692
713
true,
@@ -703,6 +724,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
703
724
TransactionId copy_xmin ;
704
725
TransactionId copy_catalog_xmin ;
705
726
XLogRecPtr copy_restart_lsn ;
727
+ XLogRecPtr copy_confirmed_flush ;
706
728
bool copy_islogical ;
707
729
char * copy_name ;
708
730
@@ -714,6 +736,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
714
736
copy_xmin = src -> data .xmin ;
715
737
copy_catalog_xmin = src -> data .catalog_xmin ;
716
738
copy_restart_lsn = src -> data .restart_lsn ;
739
+ copy_confirmed_flush = src -> data .confirmed_flush ;
717
740
718
741
/* for existence check */
719
742
copy_name = pstrdup (NameStr (src -> data .name ));
@@ -738,6 +761,14 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
738
761
NameStr (* src_name )),
739
762
errdetail ("The source replication slot was modified incompatibly during the copy operation." )));
740
763
764
+ /* The source slot must have a consistent snapshot */
765
+ if (src_islogical && XLogRecPtrIsInvalid (copy_confirmed_flush ))
766
+ ereport (ERROR ,
767
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
768
+ errmsg ("cannot copy unfinished logical replication slot \"%s\"" ,
769
+ NameStr (* src_name )),
770
+ errhint ("Retry when the source replication slot's confirmed_flush_lsn is valid." )));
771
+
741
772
/* Install copied values again */
742
773
SpinLockAcquire (& MyReplicationSlot -> mutex );
743
774
MyReplicationSlot -> effective_xmin = copy_effective_xmin ;
@@ -746,6 +777,7 @@ copy_replication_slot(FunctionCallInfo fcinfo, bool logical_slot)
746
777
MyReplicationSlot -> data .xmin = copy_xmin ;
747
778
MyReplicationSlot -> data .catalog_xmin = copy_catalog_xmin ;
748
779
MyReplicationSlot -> data .restart_lsn = copy_restart_lsn ;
780
+ MyReplicationSlot -> data .confirmed_flush = copy_confirmed_flush ;
749
781
SpinLockRelease (& MyReplicationSlot -> mutex );
750
782
751
783
ReplicationSlotMarkDirty ();
0 commit comments