public inbox for [email protected]  
help / color / mirror / Atom feed
From: Amit Kapila <[email protected]>
To: Dilip Kumar <[email protected]>
Cc: vignesh C <[email protected]>
Cc: Nisha Moond <[email protected]>
Cc: shveta malik <[email protected]>
Cc: Peter Smith <[email protected]>
Cc: Masahiko Sawada <[email protected]>
Cc: Bharath Rupireddy <[email protected]>
Cc: PostgreSQL Hackers <[email protected]>
Subject: Re: Proposal: Conflict log history table for Logical Replication
Date: Wed, 24 Jun 2026 16:31:54 +0530
Message-ID: <CAA4eK1KsF+v3v6wOoWDWzj3fb_1kDi9dpf+aHdjz=2-k_C3mrg@mail.gmail.com> (raw)
In-Reply-To: <CAFiTN-vvJ42f4Bs679gVxBH8BpqmOskW1bnOUTUpy-x0L2wz_g@mail.gmail.com>
References: <CAFiTN-u5D5o_AGNbHRZHaOqAMWkxLf+hSk_r9X3gv6HbLOB5+g@mail.gmail.com>
	<CALj2ACViThGQDYi-yeqUeHqG2Pozn2AiyvtDtjE6zhhbM0KsEA@mail.gmail.com>
	<CAA4eK1+44b3vd_OWfiaVNtjf5Njb5cek09pmKRmttBByeg0NoA@mail.gmail.com>
	<CAFiTN-v3L0WacCDx5dkOSonaZQbJfstXL4HrCPD1ahRdUsRnSg@mail.gmail.com>
	<CALj2ACW63uuxh0fSoxEAF8OMWhz1dJKSkp268WJDzf5BUqCf5g@mail.gmail.com>
	<CAFiTN-s9WWLOhW1TO27NtJwGf0bh2+MWyp3NEkZFeN_S5_p_rA@mail.gmail.com>
	<CAA4eK1LxnsEx5sMbQkK5MHAgXKPROMQXQ0n=fKMwz+UsfKQaMQ@mail.gmail.com>
	<CAD21AoDj+c4LXf2y4ESR-gVyv9d8V0G4R8R9pn-PcmT5zPzYcg@mail.gmail.com>
	<CAA4eK1KokmAwNOL6bS-ip_E3F96PiQTjC4j-M+5vD1T6uUyi3Q@mail.gmail.com>
	<CAFiTN-vFKE8E_N6h+peX9DP92mxCeFdm5A9Esn4DkLmNcZ-dOA@mail.gmail.com>
	<CAFiTN-shLYf-fOTQ_dBf3Xfx05gxs_8d93MHZXyyz6w2Bg5geQ@mail.gmail.com>
	<CAFiTN-tEgkKQHUikn6iBFCYf7XOObR7ncUq=OVh7WEk=6P4ymw@mail.gmail.com>
	<CAFiTN-tQiakd8m+-d6WN6RpJXSv_JcropZ2oGzme4d1JudQhYg@mail.gmail.com>
	<CAJpy0uDKbYWt+YPADj=4fHEvrGEWgnG1n_YsiGT_EZiZf0VSAw@mail.gmail.com>
	<CAFiTN-t82BiXen+HfdR9jZyOpuSO92xonnUK=khXsiZWBfOxMA@mail.gmail.com>
	<CAJpy0uAu2paxGAEffD=vaBTW9Jqbtxxawb8K8FgiASfeKPnGog@mail.gmail.com>
	<CAJpy0uC0ZWgHOivJ102A1fMkppwK3RuSMafRPKyjwkmJrjhVUw@mail.gmail.com>
	<CAFiTN-vFV9-zajrwjYHYyFnyQsooOAXW4CpxB5f-iT3APjOtoQ@mail.gmail.com>
	<CAJpy0uBeU1dZgaqsSVKc=P=EVUKxRgVuHR8jDXFL-HLibbE-kQ@mail.gmail.com>
	<CAA4eK1+FOkOxhzVLAnDymoNjp4i98H-L1+ZsWDgJEv-ndnTzTA@mail.gmail.com>
	<CAFiTN-sVK6Bp+BawCJU_WpAXQSTX4OkKmce5EE4YNBgD-XSjZw@mail.gmail.com>
	<CAA4eK1LbjV0bctib9wUnBpEkC+2rZFPnGuRtrKuc5AtUAzum+A@mail.gmail.com>
	<CAFiTN-vq50N3QP9p3_SH+tJ8Pn=uRDb0X4qEcQZYcGW9AX88rQ@mail.gmail.com>
	<CAFiTN-u3+zRGPESP5kUUfa6NxaWh1HL-gd1225KJ0Uvzi1urow@mail.gmail.com>
	<CAA4eK1L4iNk6mNTC83PbYrRfUdtivH4U961PkdFfOO7mvc=USg@mail.gmail.com>
	<CAFiTN-v+Mh64UfR5zb5rwgyGm6HS80XRSZ_XeaWkg8=+s9o3Kg@mail.gmail.com>
	<CAFiTN-s3ZFHteQsiC3H4=AjTWxuwN-w69XQ3xL5X6YOMTua4pA@mail.gmail.com>
	<CAJpy0uDe724nY59j-8hMapZ_Fru1Wo-NucF4Ea1B3Jrw=+J+UQ@mail.gmail.com>
	<CAFiTN-uR=86L_5tyiA7n73EXCSCuDfQKfL5O=c8n7zZom8_ONQ@mail.gmail.com>
	<CAD21AoDfOS-J0M9WbM3D20eGbSPzbfLQ-9XoYkxO4AZ9twqyvg@mail.gmail.com>
	<CAFiTN-vMTg2X7vwfHLr5Gvy8ViV63_iaEcpHmM8V5GpA9-u8cg@mail.gmail.com>
	<CAA4eK1+b2Ws0e_ZYJsgZAPn7VWndxAK_YM_QMKcfXst3e7F6Jg@mail.gmail.com>
	<CAFiTN-v6hFKMPrSyTBsz=AtEETYMbOxrqvhZJsPQqKgQc4WCLw@mail.gmail.com>
	<CAA4eK1KV3rYkaxys5fh-PtE9kq5xrFbiaRpOSPoRgQG494ek+g@mail.gmail.com>
	<CAFiTN-utvu=QjY1QQ1a_TvkpkpvesMWo9M8wTFYLaOTPdpOJvw@mail.gmail.com>
	<CAA4eK1+HoSOEqNwT3twArPNx4_D7hSUoEg2LnYhX8n9iUwhXgQ@mail.gmail.com>
	<CAFiTN-tqmsfW0Sk=1RhzuduxqLrf9KEc8VOvBae+4aYxWTJwuA@mail.gmail.com>
	<CAA4eK1JmCQ=DHe3HsqpX+P3mGDUd_Z7E7oAxdstK6822W6tuCw@mail.gmail.com>
	<CAFiTN-uE4eAUYewuq3c5deAt3TtVork+H6rkUHRv68cOGr5rmQ@mail.gmail.com>
	<CAFiTN-sJbhPX+LbA8YuQeYJpfGA2XA+OKXf8jCm04RoJOyzLvw@mail.gmail.com>
	<CAJpy0uBPOyWj9itFjHzGXfrUuYS8KGmAvgdcV_9FPjWZ0EZz_w@mail.gmail.com>
	<CAFiTN-s=iLE4qM4qmw9yXKqW09R_c_HqaSGeZXJ2EaTVfXss+g@mail.gmail.com>
	<CAA4eK1KYo0vZpPSRc_4gVpa06-J39gxjs3tHFyckgkBfYJSfFA@mail.gmail.com>
	<CAFiTN-vrKc6OWzrg6yvpwYcj79k=zkrDp3uwiZzjwrWLJAq6tw@mail.gmail.com>
	<CAA4eK1LmvrfEgn1NUZZ=E3yMCjQdNZ5=_SBEry73-EmF6jM_PQ@mail.gmail.com>
	<CAFiTN-vjfub5b3PqPQzfOw9BSjm8jt28ott+Hoz9CrRxJHzYkg@mail.gmail.com>
	<CAFiTN-v=ANapYvRK+SOy2wJb4CSuD6Vb6_bTGuReM9Dv+3tucA@mail.gmail.com>
	<CALDaNm1zEYoSdf2Ns-=UJRw95E5sbfpB0oaNUWtRJN27Q1Knhw@mail.gmail.com>
	<CALDaNm3USsXVNBsfdpkp60HVgrTV4taWMk1xZYNBa7QUF=V0jg@mail.gmail.com>
	<CAFiTN-sNg9ghLNkB2Kn0SwBGOub9acc99XZZU_d5NAcyW-yrEg@mail.gmail.com>
	<CAJpy0uAF3EYcYdpTHdKMeXfvaPbNvnWrZUATrSLL1hqjao=33A@mail.gmail.com>
	<CAFiTN-uikggCKp2LscTorKY5d3KF9j93DW0xebDcRX86G+ZsSw@mail.gmail.com>
	<CAJpy0uDaOoVK8S3_xxTAcTDpfK1AY7tApw7nPOZG_gUz+DMi=Q@mail.gmail.com>
	<CAA4eK1+AdeC5B9xrAXSKWGtTh-0d8xdD=fZttmOBm+c8o8thAQ@mail.gmail.com>
	<CAFiTN-skBQAeuzuUd+PDK0Gqc8g+4x9ypBMwJhOrmW8ZCFKGSA@mail.gmail.com>
	<CAJpy0uCdrsW5T+okq7xTOVxagje7FW3DOeY5B0CGKYa5VqF_tQ@mail.gmail.com>
	<CAFiTN-u+_mFj9caYYFO7=_YHFXk5y=vvOm2H2=5hctYktmAVGA@mail.gmail.com>
	<CALDaNm1aivk9KgQ5daeF6YZzuE+0wWc2yb7wb6qikNyvfPN0Sg@mail.gmail.com>
	<CAJpy0uD6fTEUYJx3+yDbvB=VW7c5AaGoeSd7iwHdYYO=kYGn3g@mail.gmail.com>
	<CALDaNm2YOOdJ25X1sJ+DYz37K6Qi4g0ZNFHb_pQMF9UqancnEA@mail.gmail.com>
	<CAHut+PtMS5bENS0DVtBj+s3kUEOq61+hSkqLODjFB78egB0imQ@mail.gmail.com>
	<CAFiTN-s_M83sfs+MHHbUrMesjsCPN4JWxY5MChCEiY1U-u7=9g@mail.gmail.com>
	<CAFiTN-vj8NTm9w_L2XdhxJCub_RZw__YVUgfXa1B1kJzJctRNw@mail.gmail.com>
	<CAJpy0uBDLnfhuSiev8W9ZMFNTzUmqhds2dKayUpLoN-z1dtsLA@mail.gmail.com>
	<CAFiTN-uL9f0X+=Ep4BbAPvaTJA7S4XHM--G4BsnPJw4uJW7EGQ@mail.gmail.com>
	<CAJpy0uDG=t-y_m8t1zpBzfz9viP3K8dyQgkruaraVT85UtTkrg@mail.gmail.com>
	<CAFiTN-tR8Rhs8uhfbck0Ac4dd1MopvvYgjK39nWyNXRp9Z3Qww@mail.gmail.com>
	<CAA4eK1Kf15UpNmpTTE2XyX=9PE_oTpOoy5xqg3rFWbxwwP4Rbg@mail.gmail.com>
	<CAFiTN-tNqb0vjuadDz-as67ksSXa=aEK+JW=4b54RVmkUK1m2Q@mail.gmail.com>
	<CAFiTN-vDCxx6ydUFo59L8qNBbierg4as3TGPPiavR7UZjYurzA@mail.gmail.com>
	<CAHut+PsWms218ENALnytLEV4NpxjOrAYhChLDaMaeE65-vNgrQ@mail.gmail.com>
	<CAFiTN-v9i9RmDvdUmtMUow4=b+nr0k7LKMyEQ+6ZF=EVdfBhBA@mail.gmail.com>
	<CALDaNm2YTKwPDjt9OV49RgM0zbkWhMhNu228bj_7f+zzcPb-ew@mail.gmail.com>
	<CAFiTN-t_4XvofM3an-WmykqnPE+9wf9U+o2M7p1CWd9eXkN88Q@mail.gmail.com>
	<CAHut+PuaqNDfDu_3xkZR4OYxw-B7ew_WjpLXCBvMcSBJz2K6Xg@mail.gmail.com>
	<CAFiTN-uqNN9S_hRuda_th5MEpywa15g+XO00yM6tNJ-spGRRJw@mail.gmail.com>
	<CABdArM6QxXatkGefTHy__HgaYHBvbKesffeXzT8Vn-kvcvGK4w@mail.gmail.com>
	<CAFiTN-tgMWr=TGPhs9BxaPuSC_jhM7sJJ4fHedE5W6=h40jLfA@mail.gmail.com>
	<CABdArM5fgzfyC2mH3YGB8t8cJBHWqAG1BS6rJMk7mX-8=9d=Cg@mail.gmail.com>
	<CABdArM568KF4WXdFX_aZkCiDK8R71Wpep0gC2a+cV8BMobwkrg@mail.gmail.com>
	<CAFiTN-vQ0tu18BD3UmKPb0rzZyFMQAVgGbdpMA8iYLX7PZOqOA@mail.gmail.com>
	<CALDaNm20PDtmG2E3qaTC+YuL5twv+c9k573wL3sb=OwgmZphxQ@mail.gmail.com>
	<CAA4eK1LhOHa_TEznw+gFoq+w0vMvvsDG2g9Xq8Mwa8xZMY73og@mail.gmail.com>
	<CAFiTN-vPDqrQ2rHykNgd+groFxqwBYFQF97R-Co2EmtUkV6MTg@mail.gmail.com>
	<CAFiTN-vsd=wNiEPXPQhZnipAb--+mBUC01M-pcjBjbRockgCUA@mail.gmail.com>
	<CAJpy0uCjSq_gUCJBfURhqtB6bLvkKSUL-sVXpaGKjEapv5+t+Q@mail.gmail.com>
	<CAFiTN-uZ-LaStAY3NuCY-nb7GCB9joiHX7HtHEMseJ0xfnqVSg@mail.gmail.com>
	<CAFiTN-vhJxRW5NQ628oidnk0KtHwKt11dW9-+vxqpXLTgjiYiA@mail.gmail.com>
	<CALDaNm1cJURibYKY4+DuNosjM72C9oGheUF-roMyff__+AsKBw@mail.gmail.com>
	<CAJpy0uD1_77TDAFc4jE-94X-WUus7Q3gGU0pXfC+Tticq1hFvA@mail.gmail.com>
	<CAA4eK1LFcSc4XCj4mU-cv27F_6n6=+ehJ=YAsAnyBbz4Sv_tVg@mail.gmail.com>
	<CAFiTN-s5ZtjXKrSbam7TNWJ9Ax-kCancXcestAnx2by7dK0-UA@mail.gmail.com>
	<CAFiTN-u=Da32mXyz8jocEGtuLSG4ccXXj_aEzUTPp2zkLb3MVA@mail.gmail.com>
	<CALDaNm1qY5e0thfsDB2uWXqZn4hgTWTxiUDwcF1hWA-jodsKYg@mail.gmail.com>
	<CALDaNm1nFtv3dtdRdbqWo2Rf_av7XbxDfK1Orqjcqs_Su_cLRQ@mail.gmail.com>
	<CABdArM7R498qC5Fr42aU_q-2Sc5QsT4dyKgmO_f6Uy=8oCAFXA@mail.gmail.com>
	<CAFiTN-sRZ+Z_9B3ue2L4zkbcfmPjjcAjcR1C+px1PyAs+HGsSg@mail.gmail.com>
	<CAFiTN-sdcjf9xJ2M-=ab5e4y662tTmFFiP4gHL44tC9PcQozcw@mail.gmail.com>
	<CALDaNm2WNjaNxUijVkvT6y69D62rfCu8OMwU-Pf-84un2r_=ig@mail.gmail.com>
	<CAHut+PvEP5uUR13xJ3gbNKGU49=Rg32DXMGZ2wL9jTcKHyN_=Q@mail.gmail.com>
	<CALDaNm3Jb5AQTsFJFxYZZJCaheT7qToCZkEALfW-vsMMFxjOyQ@mail.gmail.com>
	<CAHut+PtQn5U9i00qvBmjo0KBxyb+ZmBb38NzF91KnX4J86Jg_g@mail.gmail.com>
	<CALDaNm1a1gzy0L38U394_4OFwGUS8ALgSONYj++VLimY0g9piQ@mail.gmail.com>
	<CABdArM5X63AdtS99QKGjVijUd_Q_dV8QUDSo4nTHKJjn3JwtAg@mail.gmail.com>
	<CAA4eK1+h=QV4Zi=PW8Zt2D6be5ki5Mu2HgdXcfUophptx6Mt_A@mail.gmail.com>
	<CAFiTN-s-tuxar9Dp5He0CFa1pzfy1fmiwcBj6PtwD0hDodE5ng@mail.gmail.com>
	<CAFiTN-sx=k+Th=uYsrLcS6YMZbPVi9Wrggn1w2Nzf9MLEU7YRQ@mail.gmail.com>
	<CAFiTN-u5pcgAhXyJgj+p7-xmShtp0i8xA000tzjCLFQp_zMXUA@mail.gmail.com>
	<CAFiTN-tRpS7b3qFqckqFtHETj0jyzj-8SxC1arjfwf-hQd47PQ@mail.gmail.com>
	<CABdArM5Ka_m_GWhL_zZbeDPKmL-Wezwb4A-NHnO-v-fRDuhA-Q@mail.gmail.com>
	<CAFiTN-sqEMAbZ2pTt=zMa=918NV7HVeXF4bCOF+swtzKnTy5yQ@mail.gmail.com>
	<CALDaNm0WX0Vqoy2UQZh-2TpWraf4OYn28kWe9aGR=vxKwLA+bw@mail.gmail.com>
	<CAJpy0uAA_XszCAcoBuCUM3VobD39DbMDwCPUT+XW7wFfE+_E8w@mail.gmail.com>
	<CAFiTN-urKwsdyFvwz1go_C7jJFtLA8TJEhnaECAjuqkRk_1cXA@mail.gmail.com>
	<CAJpy0uBhJGqD+OyA9Uk8bHyk61XWHEf3Le1QxkotwOLcQCqaZA@mail.gmail.com>
	<CAFiTN-sbAXS6deUarPDunj2U+A6Dvhw_TASy4oMv4Tc63-_T9g@mail.gmail.com>
	<CAJpy0uBaW7ziTsHOu_z37-epihxx3qGMjqdV+_-Z-RFjq5EOGg@mail.gmail.com>
	<CAFiTN-sxVPbuqHjz99NGTz5UU0xgegsvpRa6=NkbP8_iW+X6-A@mail.gmail.com>
	<CAJpy0uBs6D9ojMpz4MWgrxDbvRxqnvN+B+JnMNezBtuvhk_j9A@mail.gmail.com>
	<CAFiTN-urmbTtk40RfLU8UMYtzk-_DLXwui3_G+TWp6XYKBphjw@mail.gmail.com>
	<CABdArM5dtMEUw14-aDSht2Vh1tsgO67t_ZU8VQp=Ut7MwK5aEQ@mail.gmail.com>
	<CAJpy0uBSY7zTH=4TvAOS=kj9vivBUc9NO+Vp6KNw-Na9RiAsMg@mail.gmail.com>
	<CAFiTN-vqyo2=pgA_jUyQoWrOwUXxw1s3aYHcZBr_EHsztZN9jg@mail.gmail.com>
	<CAJpy0uDGuaEvBym5VnE4mXJ_meo3jR7uG=c6wVbDAiuTjHcwrg@mail.gmail.com>
	<CAA4eK1JhZYRMP_YYa1j3uAK6L4v057JDuM0+YLABOgAOYuwM8Q@mail.gmail.com>
	<CABdArM6r0u6e2HQY3CQ15uZwOD2iTtVndecsNyK4R5tX9+eaNQ@mail.gmail.com>
	<CAFiTN-tnBhCU8opWAjp1xYkjqGeXtQ1tfDZHbYBS7TifymXEvw@mail.gmail.com>
	<CALDaNm0siWVCuTg6S8Xbk5SMHc91AX8Y+fAtOyV+cjwcpiFDWQ@mail.gmail.com>
	<CAFiTN-vvJ42f4Bs679gVxBH8BpqmOskW1bnOUTUpy-x0L2wz_g@mail.gmail.com>

On Wed, Jun 24, 2026 at 12:53 PM Dilip Kumar <[email protected]> wrote:
>
> On Tue, Jun 23, 2026 at 2:22 PM vignesh C <[email protected]> wrote:
> >
> > Few comments:
> > 1) Currently we are storing these in shared memory. Looking at the
> > implementation, these fields are purely worker-private state used to
> > ferry data across the error boundary from prepare_conflict_log_tuple()
> > (inside the PG_TRY block) to ProcessPendingConflictLogTuple() (inside
> > the PG_CATCH block).

Good point.

If it is not required by another process, should
> > it be moved out of shared memory.
> > +       /* A conflict log tuple that is prepared but not yet inserted. */
> > +       HeapTuple       conflict_log_tuple;
> > +
> > +       /*
> > +        * Error-context string describing the conflict above, used to
> > annotate any
> > +        * error raised while inserting conflict_log_tuple into the conflict log
> > +        * table.  Allocated, like conflict_log_tuple, in ApplyContext.
> > +        */
> > +       char       *conflict_log_errcontext;
>
> Yeah there is no need for them to be in shared memory, but do we have
> any other data sturcture where these fits naturally, or we can make
> them global variables?
>

Or we can have a file local struct PendingConflictLogData similar to
FlushPosition. See the attached top-up patch. As the comment
("Allocated, like conflict_log_tuple, in ApplyContext") says it is
allocated in process-local Apply context, it is not safe to keep them
in shared memory.

>
> > 4) Is the condition remote_commit_ts > 0 done intentionally?
> > +       if (remote_commit_ts > 0)
> > +               values[attno++] = TimestampTzGetDatum(remote_commit_ts);
> > +       else
> > +               nulls[attno++] = true;
> >
> > As I had seen some negative values for certain timestamps. Shouldn't
> > the check be != 0?
> > SELECT extract(epoch FROM '1969-12-31 23:59:59+00'::timestamptz);
> >   extract
> > -----------
> >  -1.000000
> > (1 row)
>
> I think the 0 can also be generated for timestamptz, but since we are
> initializing `timestamptz` with 0, checking it seems correct.= 0, but
> I need to put more thought into this.
>

I think either way (>0 or !=0) are fine as both will serve the desired
purpose but I think !=0 will be more robust because we are using 0 as
sentinel value for remote_commit_ts.

-- 
With Regards,
Amit Kapila.

From 773671f06bf3c2e577d0ad99d40a23b84cae9258 Mon Sep 17 00:00:00 2001
From: Amit Kapila <[email protected]>
Date: Wed, 24 Jun 2026 16:08:18 +0530
Subject: [PATCH v1_amit] Move pending conflict log state out of shared memory

The prepared conflict tuple and its error-context string are purely
worker-private data ferried across the apply error boundary, so keep them in a
process-local static struct in conflict.c instead of the shared LogicalRepWorker.
---
 src/backend/replication/logical/conflict.c | 67 ++++++++++++++--------
 src/backend/replication/logical/launcher.c |  1 -
 src/include/replication/worker_internal.h  | 10 ----
 3 files changed, 43 insertions(+), 35 deletions(-)

diff --git a/src/backend/replication/logical/conflict.c b/src/backend/replication/logical/conflict.c
index 983cdf94cf0..e927c152028 100644
--- a/src/backend/replication/logical/conflict.c
+++ b/src/backend/replication/logical/conflict.c
@@ -101,6 +101,25 @@ static const char *const ConflictTypeNames[] = {
 	[CT_MULTIPLE_UNIQUE_CONFLICTS] = "multiple_unique_conflicts"
 };
 
+/*
+ * Worker-private state for a conflict that has been prepared for the conflict
+ * log table but not yet inserted.  It carries the prepared tuple, and a
+ * description of the conflict used for error context, from
+ * prepare_conflict_log_tuple() across the apply error boundary to
+ * ProcessPendingConflictLogTuple()/InsertConflictLogTuple().  Both pointers
+ * reference memory allocated in ApplyContext.
+ *
+ * This is purely process-local state, so it lives here rather than in the
+ * shared LogicalRepWorker struct.
+ */
+typedef struct PendingConflictLogData
+{
+	HeapTuple	tuple;			/* prepared, not-yet-inserted conflict tuple */
+	char	   *errcontext_str;	/* conflict description for error context */
+} PendingConflictLog;
+
+static PendingConflictLog pending_conflict_log = {0};
+
 static int	errcode_apply_conflict(ConflictType type);
 static void errdetail_apply_conflict(EState *estate,
 									 ResultRelInfo *relinfo,
@@ -427,15 +446,15 @@ ReportApplyConflict(EState *estate, ResultRelInfo *relinfo, int elevel,
 				 * insertion path (ProcessPendingConflictLogTuple) does not retry
 				 * this same failing insert.
 				 */
-				if (MyLogicalRepWorker->conflict_log_tuple != NULL)
+				if (pending_conflict_log.tuple != NULL)
 				{
-					heap_freetuple(MyLogicalRepWorker->conflict_log_tuple);
-					MyLogicalRepWorker->conflict_log_tuple = NULL;
+					heap_freetuple(pending_conflict_log.tuple);
+					pending_conflict_log.tuple = NULL;
 				}
-				if (MyLogicalRepWorker->conflict_log_errcontext != NULL)
+				if (pending_conflict_log.errcontext_str != NULL)
 				{
-					pfree(MyLogicalRepWorker->conflict_log_errcontext);
-					MyLogicalRepWorker->conflict_log_errcontext = NULL;
+					pfree(pending_conflict_log.errcontext_str);
+					pending_conflict_log.errcontext_str = NULL;
 				}
 				PG_RE_THROW();
 			}
@@ -468,7 +487,7 @@ ProcessPendingConflictLogTuple(void)
 	Relation	conflictlogrel;
 
 	/* Nothing to do */
-	if (MyLogicalRepWorker->conflict_log_tuple == NULL)
+	if (pending_conflict_log.tuple == NULL)
 		return;
 
 	/*
@@ -499,12 +518,12 @@ ProcessPendingConflictLogTuple(void)
 		 * ReportApplyConflict().  Nothing more to do; just discard the prepared
 		 * tuple and its context string.
 		 */
-		heap_freetuple(MyLogicalRepWorker->conflict_log_tuple);
-		MyLogicalRepWorker->conflict_log_tuple = NULL;
-		if (MyLogicalRepWorker->conflict_log_errcontext)
+		heap_freetuple(pending_conflict_log.tuple);
+		pending_conflict_log.tuple = NULL;
+		if (pending_conflict_log.errcontext_str)
 		{
-			pfree(MyLogicalRepWorker->conflict_log_errcontext);
-			MyLogicalRepWorker->conflict_log_errcontext = NULL;
+			pfree(pending_conflict_log.errcontext_str);
+			pending_conflict_log.errcontext_str = NULL;
 		}
 	}
 
@@ -634,7 +653,7 @@ InsertConflictLogTuple(Relation conflictlogrel)
 	ErrorContextCallback errcallback;
 
 	/* A valid tuple must be prepared and stored in MyLogicalRepWorker. */
-	Assert(MyLogicalRepWorker->conflict_log_tuple != NULL);
+	Assert(pending_conflict_log.tuple != NULL);
 
 	/*
 	 * Set up an error context so that a failure to insert (e.g. the conflict
@@ -642,22 +661,22 @@ InsertConflictLogTuple(Relation conflictlogrel)
 	 * identifying the conflict we were trying to log.
 	 */
 	errcallback.callback = conflict_log_insert_errcontext;
-	errcallback.arg = MyLogicalRepWorker->conflict_log_errcontext;
+	errcallback.arg = pending_conflict_log.errcontext_str;
 	errcallback.previous = error_context_stack;
 	error_context_stack = &errcallback;
 
-	heap_insert(conflictlogrel, MyLogicalRepWorker->conflict_log_tuple,
+	heap_insert(conflictlogrel, pending_conflict_log.tuple,
 				GetCurrentCommandId(true), HEAP_INSERT_NO_LOGICAL, NULL);
 
 	error_context_stack = errcallback.previous;
 
 	/* Free the conflict log tuple and its context string. */
-	heap_freetuple(MyLogicalRepWorker->conflict_log_tuple);
-	MyLogicalRepWorker->conflict_log_tuple = NULL;
-	if (MyLogicalRepWorker->conflict_log_errcontext)
+	heap_freetuple(pending_conflict_log.tuple);
+	pending_conflict_log.tuple = NULL;
+	if (pending_conflict_log.errcontext_str)
 	{
-		pfree(MyLogicalRepWorker->conflict_log_errcontext);
-		MyLogicalRepWorker->conflict_log_errcontext = NULL;
+		pfree(pending_conflict_log.errcontext_str);
+		pending_conflict_log.errcontext_str = NULL;
 	}
 }
 
@@ -1394,7 +1413,7 @@ build_local_conflicts_json_array(EState *estate, Relation rel,
  *
  * This routine prepares a tuple detailing a conflict encountered during
  * logical replication. The prepared tuple will be stored in
- * MyLogicalRepWorker->conflict_log_tuple which should be inserted into the
+ * pending_conflict_log.tuple which should be inserted into the
  * conflict log table by calling InsertConflictLogTuple.
  */
 static void
@@ -1411,7 +1430,7 @@ prepare_conflict_log_tuple(EState *estate, Relation rel,
 	char	   *remote_origin = NULL;
 	MemoryContext	oldctx;
 
-	Assert(MyLogicalRepWorker->conflict_log_tuple == NULL);
+	Assert(pending_conflict_log.tuple == NULL);
 
 	/* Populate the values and nulls arrays. */
 	attno = 0;
@@ -1475,7 +1494,7 @@ prepare_conflict_log_tuple(EState *estate, Relation rel,
 	Assert(attno + 1 == NUM_CONFLICT_ATTRS);
 
 	oldctx = MemoryContextSwitchTo(ApplyContext);
-	MyLogicalRepWorker->conflict_log_tuple =
+	pending_conflict_log.tuple =
 		heap_form_tuple(RelationGetDescr(conflictlogrel), values, nulls);
 
 	/*
@@ -1483,7 +1502,7 @@ prepare_conflict_log_tuple(EState *estate, Relation rel,
 	 * the tuple into the conflict log table fails, the resulting error carries
 	 * enough context to identify the conflict (see InsertConflictLogTuple).
 	 */
-	MyLogicalRepWorker->conflict_log_errcontext =
+	pending_conflict_log.errcontext_str =
 		psprintf("while logging conflict \"%s\" detected on relation \"%s\"",
 				 ConflictTypeNames[conflict_type],
 				 RelationGetRelationName(rel));
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 05a30342f69..313e31ff2e3 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -487,7 +487,6 @@ retry:
 	worker->oldest_nonremovable_xid = retain_dead_tuples
 		? MyReplicationSlot->data.xmin
 		: InvalidTransactionId;
-	worker->conflict_log_tuple = NULL;
 	worker->last_lsn = InvalidXLogRecPtr;
 	TIMESTAMP_NOBEGIN(worker->last_send_time);
 	TIMESTAMP_NOBEGIN(worker->last_recv_time);
diff --git a/src/include/replication/worker_internal.h b/src/include/replication/worker_internal.h
index 79c90dddd89..00ad0d86a79 100644
--- a/src/include/replication/worker_internal.h
+++ b/src/include/replication/worker_internal.h
@@ -100,16 +100,6 @@ typedef struct LogicalRepWorker
 	 */
 	TransactionId oldest_nonremovable_xid;
 
-	/* A conflict log tuple that is prepared but not yet inserted. */
-	HeapTuple	conflict_log_tuple;
-
-	/*
-	 * Error-context string describing the conflict above, used to annotate any
-	 * error raised while inserting conflict_log_tuple into the conflict log
-	 * table.  Allocated, like conflict_log_tuple, in ApplyContext.
-	 */
-	char	   *conflict_log_errcontext;
-
 	/* Stats. */
 	XLogRecPtr	last_lsn;
 	TimestampTz last_send_time;
-- 
2.54.0



Attachments:

  [text/plain] v1_amit-0001-Move-pending-conflict-log-state-out-of-share.txt (8.1K, 2-v1_amit-0001-Move-pending-conflict-log-state-out-of-share.txt)
  download | inline diff:
From 773671f06bf3c2e577d0ad99d40a23b84cae9258 Mon Sep 17 00:00:00 2001
From: Amit Kapila <[email protected]>
Date: Wed, 24 Jun 2026 16:08:18 +0530
Subject: [PATCH v1_amit] Move pending conflict log state out of shared memory

The prepared conflict tuple and its error-context string are purely
worker-private data ferried across the apply error boundary, so keep them in a
process-local static struct in conflict.c instead of the shared LogicalRepWorker.
---
 src/backend/replication/logical/conflict.c | 67 ++++++++++++++--------
 src/backend/replication/logical/launcher.c |  1 -
 src/include/replication/worker_internal.h  | 10 ----
 3 files changed, 43 insertions(+), 35 deletions(-)

diff --git a/src/backend/replication/logical/conflict.c b/src/backend/replication/logical/conflict.c
index 983cdf94cf0..e927c152028 100644
--- a/src/backend/replication/logical/conflict.c
+++ b/src/backend/replication/logical/conflict.c
@@ -101,6 +101,25 @@ static const char *const ConflictTypeNames[] = {
 	[CT_MULTIPLE_UNIQUE_CONFLICTS] = "multiple_unique_conflicts"
 };
 
+/*
+ * Worker-private state for a conflict that has been prepared for the conflict
+ * log table but not yet inserted.  It carries the prepared tuple, and a
+ * description of the conflict used for error context, from
+ * prepare_conflict_log_tuple() across the apply error boundary to
+ * ProcessPendingConflictLogTuple()/InsertConflictLogTuple().  Both pointers
+ * reference memory allocated in ApplyContext.
+ *
+ * This is purely process-local state, so it lives here rather than in the
+ * shared LogicalRepWorker struct.
+ */
+typedef struct PendingConflictLogData
+{
+	HeapTuple	tuple;			/* prepared, not-yet-inserted conflict tuple */
+	char	   *errcontext_str;	/* conflict description for error context */
+} PendingConflictLog;
+
+static PendingConflictLog pending_conflict_log = {0};
+
 static int	errcode_apply_conflict(ConflictType type);
 static void errdetail_apply_conflict(EState *estate,
 									 ResultRelInfo *relinfo,
@@ -427,15 +446,15 @@ ReportApplyConflict(EState *estate, ResultRelInfo *relinfo, int elevel,
 				 * insertion path (ProcessPendingConflictLogTuple) does not retry
 				 * this same failing insert.
 				 */
-				if (MyLogicalRepWorker->conflict_log_tuple != NULL)
+				if (pending_conflict_log.tuple != NULL)
 				{
-					heap_freetuple(MyLogicalRepWorker->conflict_log_tuple);
-					MyLogicalRepWorker->conflict_log_tuple = NULL;
+					heap_freetuple(pending_conflict_log.tuple);
+					pending_conflict_log.tuple = NULL;
 				}
-				if (MyLogicalRepWorker->conflict_log_errcontext != NULL)
+				if (pending_conflict_log.errcontext_str != NULL)
 				{
-					pfree(MyLogicalRepWorker->conflict_log_errcontext);
-					MyLogicalRepWorker->conflict_log_errcontext = NULL;
+					pfree(pending_conflict_log.errcontext_str);
+					pending_conflict_log.errcontext_str = NULL;
 				}
 				PG_RE_THROW();
 			}
@@ -468,7 +487,7 @@ ProcessPendingConflictLogTuple(void)
 	Relation	conflictlogrel;
 
 	/* Nothing to do */
-	if (MyLogicalRepWorker->conflict_log_tuple == NULL)
+	if (pending_conflict_log.tuple == NULL)
 		return;
 
 	/*
@@ -499,12 +518,12 @@ ProcessPendingConflictLogTuple(void)
 		 * ReportApplyConflict().  Nothing more to do; just discard the prepared
 		 * tuple and its context string.
 		 */
-		heap_freetuple(MyLogicalRepWorker->conflict_log_tuple);
-		MyLogicalRepWorker->conflict_log_tuple = NULL;
-		if (MyLogicalRepWorker->conflict_log_errcontext)
+		heap_freetuple(pending_conflict_log.tuple);
+		pending_conflict_log.tuple = NULL;
+		if (pending_conflict_log.errcontext_str)
 		{
-			pfree(MyLogicalRepWorker->conflict_log_errcontext);
-			MyLogicalRepWorker->conflict_log_errcontext = NULL;
+			pfree(pending_conflict_log.errcontext_str);
+			pending_conflict_log.errcontext_str = NULL;
 		}
 	}
 
@@ -634,7 +653,7 @@ InsertConflictLogTuple(Relation conflictlogrel)
 	ErrorContextCallback errcallback;
 
 	/* A valid tuple must be prepared and stored in MyLogicalRepWorker. */
-	Assert(MyLogicalRepWorker->conflict_log_tuple != NULL);
+	Assert(pending_conflict_log.tuple != NULL);
 
 	/*
 	 * Set up an error context so that a failure to insert (e.g. the conflict
@@ -642,22 +661,22 @@ InsertConflictLogTuple(Relation conflictlogrel)
 	 * identifying the conflict we were trying to log.
 	 */
 	errcallback.callback = conflict_log_insert_errcontext;
-	errcallback.arg = MyLogicalRepWorker->conflict_log_errcontext;
+	errcallback.arg = pending_conflict_log.errcontext_str;
 	errcallback.previous = error_context_stack;
 	error_context_stack = &errcallback;
 
-	heap_insert(conflictlogrel, MyLogicalRepWorker->conflict_log_tuple,
+	heap_insert(conflictlogrel, pending_conflict_log.tuple,
 				GetCurrentCommandId(true), HEAP_INSERT_NO_LOGICAL, NULL);
 
 	error_context_stack = errcallback.previous;
 
 	/* Free the conflict log tuple and its context string. */
-	heap_freetuple(MyLogicalRepWorker->conflict_log_tuple);
-	MyLogicalRepWorker->conflict_log_tuple = NULL;
-	if (MyLogicalRepWorker->conflict_log_errcontext)
+	heap_freetuple(pending_conflict_log.tuple);
+	pending_conflict_log.tuple = NULL;
+	if (pending_conflict_log.errcontext_str)
 	{
-		pfree(MyLogicalRepWorker->conflict_log_errcontext);
-		MyLogicalRepWorker->conflict_log_errcontext = NULL;
+		pfree(pending_conflict_log.errcontext_str);
+		pending_conflict_log.errcontext_str = NULL;
 	}
 }
 
@@ -1394,7 +1413,7 @@ build_local_conflicts_json_array(EState *estate, Relation rel,
  *
  * This routine prepares a tuple detailing a conflict encountered during
  * logical replication. The prepared tuple will be stored in
- * MyLogicalRepWorker->conflict_log_tuple which should be inserted into the
+ * pending_conflict_log.tuple which should be inserted into the
  * conflict log table by calling InsertConflictLogTuple.
  */
 static void
@@ -1411,7 +1430,7 @@ prepare_conflict_log_tuple(EState *estate, Relation rel,
 	char	   *remote_origin = NULL;
 	MemoryContext	oldctx;
 
-	Assert(MyLogicalRepWorker->conflict_log_tuple == NULL);
+	Assert(pending_conflict_log.tuple == NULL);
 
 	/* Populate the values and nulls arrays. */
 	attno = 0;
@@ -1475,7 +1494,7 @@ prepare_conflict_log_tuple(EState *estate, Relation rel,
 	Assert(attno + 1 == NUM_CONFLICT_ATTRS);
 
 	oldctx = MemoryContextSwitchTo(ApplyContext);
-	MyLogicalRepWorker->conflict_log_tuple =
+	pending_conflict_log.tuple =
 		heap_form_tuple(RelationGetDescr(conflictlogrel), values, nulls);
 
 	/*
@@ -1483,7 +1502,7 @@ prepare_conflict_log_tuple(EState *estate, Relation rel,
 	 * the tuple into the conflict log table fails, the resulting error carries
 	 * enough context to identify the conflict (see InsertConflictLogTuple).
 	 */
-	MyLogicalRepWorker->conflict_log_errcontext =
+	pending_conflict_log.errcontext_str =
 		psprintf("while logging conflict \"%s\" detected on relation \"%s\"",
 				 ConflictTypeNames[conflict_type],
 				 RelationGetRelationName(rel));
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 05a30342f69..313e31ff2e3 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -487,7 +487,6 @@ retry:
 	worker->oldest_nonremovable_xid = retain_dead_tuples
 		? MyReplicationSlot->data.xmin
 		: InvalidTransactionId;
-	worker->conflict_log_tuple = NULL;
 	worker->last_lsn = InvalidXLogRecPtr;
 	TIMESTAMP_NOBEGIN(worker->last_send_time);
 	TIMESTAMP_NOBEGIN(worker->last_recv_time);
diff --git a/src/include/replication/worker_internal.h b/src/include/replication/worker_internal.h
index 79c90dddd89..00ad0d86a79 100644
--- a/src/include/replication/worker_internal.h
+++ b/src/include/replication/worker_internal.h
@@ -100,16 +100,6 @@ typedef struct LogicalRepWorker
 	 */
 	TransactionId oldest_nonremovable_xid;
 
-	/* A conflict log tuple that is prepared but not yet inserted. */
-	HeapTuple	conflict_log_tuple;
-
-	/*
-	 * Error-context string describing the conflict above, used to annotate any
-	 * error raised while inserting conflict_log_tuple into the conflict log
-	 * table.  Allocated, like conflict_log_tuple, in ApplyContext.
-	 */
-	char	   *conflict_log_errcontext;
-
 	/* Stats. */
 	XLogRecPtr	last_lsn;
 	TimestampTz last_send_time;
-- 
2.54.0



view thread (161+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: Proposal: Conflict log history table for Logical Replication
  In-Reply-To: <CAA4eK1KsF+v3v6wOoWDWzj3fb_1kDi9dpf+aHdjz=2-k_C3mrg@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox