Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w2AVm-0003HD-1U for pgsql-hackers@arkaria.postgresql.org; Mon, 16 Mar 2026 16:09:46 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1w2AVk-00B6qa-1l for pgsql-hackers@arkaria.postgresql.org; Mon, 16 Mar 2026 16:09:45 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1w2AVk-00B6qS-0P for pgsql-hackers@lists.postgresql.org; Mon, 16 Mar 2026 16:09:45 +0000 Received: from mail-yx1-xb12b.google.com ([2607:f8b0:4864:20::b12b]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1w2AVh-000000002K3-28yL for pgsql-hackers@postgresql.org; Mon, 16 Mar 2026 16:09:44 +0000 Received: by mail-yx1-xb12b.google.com with SMTP id 956f58d0204a3-64ad79df972so4915363d50.1 for ; Mon, 16 Mar 2026 09:09:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1773677382; cv=none; d=google.com; s=arc-20240605; b=c7n70HfZPMy2f5z+ZTiC08jAFELX7GVxpRz2nUyudprMAoHmffpcbxAHafnVy3FZ0w zzacoOFuu0bchZbXk+omlWt2rXoCXaUXwyj7LrfScKwKCYTKOlsMA9BL0L2Zlx28XTDH 7x+PJlKeLEFogrJ/ljovj/WgXJCt6KJzD058zHRDWjgLdF+MgS0jS1fU7mgGmJ+pQMx/ Y/OIEHZW4fpsASdAttUU/SmFAK2dQZwBuCQaOUiw6pTLtu8iBRokV5iHglffcrwYbWyy 5ASFtfBCt+JoHUEPbzMmBvV0IeHXg1X/m3GDzkkCUnOz96AGWxFdpn1gW7oXBUXW8sUv XhhQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=8kZ6frTxJJyZA3JlmoBKzfubP+qwa0ZXuN1WTA3EMTA=; fh=33OU7BWuulPFH378PdKTnpeW+jw3IP20DTmpLDeQ3pE=; b=TqNWWTGdwkGBl8InnzT8OVQmuSqVDXBFYaM9TwheHPXBN6N1XyEil3N+5ocJqVa6hE S2SHuaBtrNI0/BmAoaRhGCzL2JBrqH+DjAsENg7idp4l+GxpnbJiHbaK17uW/bV45I2n eFb6EIZj008pEjygHCGEZ9R5xXqbuad0YvH2WAEti8u+7EBcd08K4FCp1P5PLIrZo0IH L0Bx51OTtJxfPD61F5X1wFaGNr1avMR8OUyFMAFq70EbmAeuZLbCdyFcSBRaLE6EmFQN BfqEeWIgtvgoYTinPJzF1cK+JPjHzPb9aw+xZk3B9JQLNJsdi04GVOPqDqvXkstYJVrA WsOg==; darn=postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1773677382; x=1774282182; darn=postgresql.org; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=8kZ6frTxJJyZA3JlmoBKzfubP+qwa0ZXuN1WTA3EMTA=; b=mHB5ViBYpmaymYTyjsWJoddPkmj5JZlR2DPsULEVF8eJWuT3f/8lf3im4+7LpvZu6s vGAa4sOKk/pIUhWjrQnpVyASw3YresH5etU4aDCKZQkzZTv/ijO+2DRaexv/vhRoAj2A +F8tLyONCVuBDcYNLI4IINoj/+cRIy6jcR2QMCKoIFivALZ+m/tX5vV5cGH66/qzmD26 6lk4oOrtZwEWNEFYxAhhhoJh+EMw+/dLogZmojkQqbC3F2ZzRshS0qne12lbfn/kUucq KC/fExVBNVjcLtD0yxQ6+TggUpQ6+vHHaG/JppleI8CKQrgw76DQzBTleBF6BshxR+uD HLqA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1773677382; x=1774282182; h=to:subject:message-id:date:from:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=8kZ6frTxJJyZA3JlmoBKzfubP+qwa0ZXuN1WTA3EMTA=; b=U+y8oAw06NtcyGyV1VQ3LcMfKzbJUYVjMihy0QIkCcn5cmQxeHsm06/Mdc8ac9lq3J YZNkxn6FlXGFijddK6g54LQS5pqnabzOJRDyP4hZSXJ7kvNjajJwMT/66s9tB81EBriG kfg+ZZIZwVT1EUI31kuC9GYc3g/PotrPMrMkNuQuDw5w0+tchab83duHIlhI7FaOyR3+ KhooSms79OHzFdepa6ayyy7C1SUbL+ft+3J0SNnpn73WJZlwzRK1Tm4FJdFkNRJ8qi5I CI2AFfR+YU8NZTpTt8gyE0IJLZAwqCQmsJvtwJuIxW5fFRzPQ6hTrwvCzkZkrsUVDhT7 9ZUA== X-Gm-Message-State: AOJu0YwIs4xnVyj84/mO3vwWmZ2HwvkeP0/FMTYpaM/lzgX15PvbWXWh EgTmUE8jmqH8erXS9uLcElyGNSvPUqQcr0zcNtXWCZ2f6M/Hgt/rtsAZiQKGl6hDXOJSS/bwyZl xezsklmTLLR9F4PhDbzttz9m3xrgZzCb5t1aSapc= X-Gm-Gg: ATEYQzwvjP5mwwppvKw/IdkPPokPIspT/kZCp40TjHBubUm8E9Z964Xn0W/SdtST5wz 07ZK4tv00TbxHZOD2JaZf3Gpn2XlLalAyjZGhuocgXO/1TxdFhtJmCW+tfLPLT/MWCToW4T/DOH dWxRU6q9xyRfhKxJ9qAAHpKZXfEx1v4Ewv/S3eTEFyWBRDFehqB+hyn8JrvihvdaekGpt/896xO hWbMzUikMtg1J4ZFEZSqSGwAoNnmjZTDvhCxS3uUzQVxA2T8qSQVsDayI+QAqaBbAS51bjDPF9T vLpvtA== X-Received: by 2002:a05:690c:e3c4:b0:79a:2f38:9ab4 with SMTP id 00721157ae682-79a2f38aba3mr81781677b3.9.1773677381912; Mon, 16 Mar 2026 09:09:41 -0700 (PDT) MIME-Version: 1.0 From: Ayush Tiwari Date: Mon, 16 Mar 2026 21:39:30 +0530 X-Gm-Features: AaiRm50yhQZ5c5hSb6gnBdMIe1O5_yHPqgmNGXtXQXuMFje06KiiXCnUTEf2Wl0 Message-ID: Subject: Proposal: Prevent Primary/Standby SLRU divergence during MultiXact truncation To: pgsql-hackers@postgresql.org Content-Type: multipart/mixed; boundary="0000000000004be1d2064d2672a9" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --0000000000004be1d2064d2672a9 Content-Type: multipart/alternative; boundary="0000000000004be1d0064d2672a7" --0000000000004be1d0064d2672a7 Content-Type: text/plain; charset="UTF-8" Hi Hackers, Looking at the MultiXact truncation behavior and reading through the recent thread regarding the 17.8 standby crashing during WAL replay (commit 8ba61bc), we noticed an architectural edge case that seems to cause a silent primary/standby SLRU divergence. I'd like to ask if this is a known accepted risk or if a patch to reorder this logic is worth exploring. The Issue: In TruncateMultiXact(), we write the truncation WAL record (WriteMTruncateXlogRec) before we actually perform the truncation via PerformOffsetsTruncation() -> SimpleLruTruncate(). The problem arises from the "apparent wraparound" safety check inside SimpleLruTruncate(). If SlruScanDirectory() detects an apparent wraparound, SimpleLruTruncate() safely bails out and skips unlinking the SLRU segments on the primary, logging: could not truncate directory "%s": apparent wraparound. However, the WAL record for the truncation has already been flushed. Standbys replay this TRUNCATE_ID WAL record and blindly delete their SLRU segments. At this point, the primary and standby have diverged. The Impact: If the standby is subsequently promoted to primary, any attempt to access rows holding those older MultiXact IDs (which the original primary decided to keep) will throw a FATAL: could not access status of transaction error, effectively resulting in data loss / inaccessible rows for the user. While the recent commits address the immediate standby crash involving latest_page_number during multixact_redo(), they don't seem to prevent the primary from emitting a "false" WAL truncation record when it abandons its own truncation. Proposed Approach: It seems safer to only emit the WAL record if we are guaranteed to follow through with the truncation. We could modify SimpleLruTruncate() to perform its safety checks first and return a boolean indicating whether the truncation is safe to proceed. TruncateMultiXact() would then only call WriteMTruncateXlogRec() and proceed with physical deletion if the check passes. I have attached a rough draft patch illustrating this sequence change. Is this a scenario the community has already considered, or is this reordering something that should be explored further to harden standby reliability? PS. Also, noticed this to be the case in clog.c file Thanks for your time. Regards, Ayush --0000000000004be1d0064d2672a7 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi Hackers,

Looking at the MultiXact truncation beh= avior and reading through the recent thread regarding the 17.8 standby cras= hing during WAL replay (commit 8ba61bc), we noticed an architectural edge c= ase that seems to cause a silent primary/standby SLRU divergence. I'd l= ike to ask if this is a known accepted risk or if a patch to reorder this l= ogic is worth exploring.

The Issue:
In TruncateMultiXact(), we wr= ite the truncation WAL record (WriteMTruncateXlogRec) before we actually pe= rform the truncation via PerformOffsetsTruncation() -> SimpleLruTruncate= ().

The problem arises from the "apparent wraparound" safe= ty check inside SimpleLruTruncate(). If SlruScanDirectory() detects an appa= rent wraparound, SimpleLruTruncate() safely bails out and skips unlinking t= he SLRU segments on the primary, logging: could not truncate directory &quo= t;%s": apparent wraparound.

However, the WAL record for the tru= ncation has already been flushed. Standbys replay this TRUNCATE_ID WAL reco= rd and blindly delete their SLRU segments. At this point, the primary and s= tandby have diverged.

The Impact:
If the standby is subsequently = promoted to primary, any attempt to access rows holding those older MultiXa= ct IDs (which the original primary decided to keep) will throw a FATAL: cou= ld not access status of transaction error, effectively resulting in data lo= ss / inaccessible rows for the user.

While the recent commits addres= s the immediate standby crash involving latest_page_number during multixact= _redo(), they don't seem to prevent the primary from emitting a "f= alse" WAL truncation record when it abandons its own truncation.
Proposed Approach:
It seems safer to only emit the WAL record if we ar= e guaranteed to follow through with the truncation. We could modify SimpleL= ruTruncate() to perform its safety checks first and return a boolean indica= ting whether the truncation is safe to proceed. TruncateMultiXact() would t= hen only call WriteMTruncateXlogRec() and proceed with physical deletion if= the check passes.

I have attached a rough draft patch illustrating = this sequence change.

Is this a scenario the community has already c= onsidered, or is this reordering something that should be explored further = to harden standby reliability?

PS. Also, noticed this to be the case= in clog.c file

Thanks for your time.

Regards,
Ayush
--0000000000004be1d0064d2672a7-- --0000000000004be1d2064d2672a9 Content-Type: application/octet-stream; name="v1-prevent-multixact-slru-divergence 2.patch" Content-Disposition: attachment; filename="v1-prevent-multixact-slru-divergence 2.patch" Content-Transfer-Encoding: base64 Content-ID: X-Attachment-Id: f_mmtdm4ym0 RnJvbSA5Yjg4MzBmZTM1YWM5YTJjMmVmYWJjMWU5MTI0NGU4YWJjZDEyMzQ1IE1vbiBTZXAgMTcg MDA6MDA6MDAgMjAwMQ0KRnJvbTogQXl1c2ggVGl3YXJpIDxheXVzaHRpd2FyaS5zbGcwMUBnbWFp bC5jb20+DQpEYXRlOiBNb24sIDE2IE1hciAyMDI2IDEyOjAwOjAwICswMDAwDQpTdWJqZWN0OiBb RHJhZnQgUGF0Y2ggdjFdIFByZXZlbnQgU0xSVSBkaXZlcmdlbmNlIGJ5IGNoZWNraW5nIHdyYXBh cm91bmQgYmVmb3JlIFdBTA0KIGZsdXNoDQoNCkluIFRydW5jYXRlTXVsdGlYYWN0KCksIGlmIFNp bXBsZUxydVRydW5jYXRlKCkgZW5jb3VudGVycyBhbiBhcHBhcmVudA0Kd3JhcGFyb3VuZCwgaXQg YWJvcnRzIHRoZSB0cnVuY2F0aW9uIHNhZmVseS4gSG93ZXZlciwgdGhlIFRSVU5DQVRFX0lEDQpX QUwgcmVjb3JkIGhhcyBhbHJlYWR5IGJlZW4gZW1pdHRlZC4gU3RhbmRieXMgYmxpbmRseSByZXBs YXkgdGhpcyByZWNvcmQNCmFuZCBkZWxldGUgdGhlaXIgU0xSVSBzZWdtZW50cy4NClRoaXMgcGF0 Y2ggb3V0bGluZXMgYSBzdHJ1Y3R1cmFsIHJlb3JkZXJpbmcgc28gd2Ugb25seSBlbWl0IHRoZQ0K VFJVTkNBVEUgV0FMIHJlY29yZCBpZiB3ZSBhcmUgZ3VhcmFudGVlZCB0byBmb2xsb3cgdGhyb3Vn aC4NCg0KLS0tDQogc3JjL2JhY2tlbmQvYWNjZXNzL3RyYW5zYW0vbXVsdGl4YWN0LmMgfCAxNiAr KysrKysrKysrKysrLS0tDQogMSBmaWxlIGNoYW5nZWQsIDEzIGluc2VydGlvbnMoKyksIDMgZGVs ZXRpb25zKC0pDQoNCmRpZmYgLS1naXQgYS9zcmMvYmFja2VuZC9hY2Nlc3MvdHJhbnNhbS9tdWx0 aXhhY3QuYyBiL3NyYy9iYWNrZW5kL2FjY2Vzcy90cmFuc2FtL211bHRpeGFjdC5jDQppbmRleCBh MWIyYzNkNGUuLmY1ZzZoN2k4aiAxMDA2NDQNCi0tLSBhL3NyYy9iYWNrZW5kL2FjY2Vzcy90cmFu c2FtL211bHRpeGFjdC5jDQorKysgYi9zcmMvYmFja2VuZC9hY2Nlc3MvdHJhbnNhbS9tdWx0aXhh Y3QuYw0KQEAgLTI5ODAsMTAgKzI5ODAsMjAgQEAgVHJ1bmNhdGVNdWx0aVhhY3QoTXVsdGlYYWN0 SWQgbmV3T2xkZXN0TXVsdGksIE9pZCBuZXdPbGRlc3RNdWx0aURCKQ0KIAlBc3NlcnQoKE15UHJv Yy0+ZGVsYXlDaGtwdEZsYWdzICYgREVMQVlfQ0hLUFRfU1RBUlQpID09IDApOw0KIAlNeVByb2Mt PmRlbGF5Q2hrcHRGbGFncyB8PSBERUxBWV9DSEtQVF9TVEFSVDsNCiANCi0JLyogV0FMIGxvZyB0 cnVuY2F0aW9uICovDQotCVdyaXRlTVRydW5jYXRlWGxvZ1JlYyhuZXdPbGRlc3RNdWx0aURCLCBu ZXdPbGRlc3RNdWx0aSwgbmV3T2xkZXN0T2Zmc2V0KTsNCisJLyogDQorCSAqIFRPRE8vRFJBRlQ6 IA0KKwkgKiBXZSBzaG91bGQgY2hlY2sgaWYgU2ltcGxlTHJ1VHJ1bmNhdGUoKSB3aWxsIGFib3J0 IGR1ZSB0byANCisJICogYXBwYXJlbnQgd3JhcGFyb3VuZCAqYmVmb3JlKiBmbHVzaGluZyB0aGUg V0FMLg0KKwkgKiANCisJICogaWYgKFNpbXBsZUxydUNoZWNrV3JhcGFyb3VuZChNdWx0aVhhY3RP ZmZzZXRDdGwsIE11bHRpWGFjdElkVG9PZmZzZXRQYWdlKG5ld09sZGVzdE11bHRpKSkgJiYNCisJ ICogICAgIFNpbXBsZUxydUNoZWNrV3JhcGFyb3VuZChNdWx0aVhhY3RNZW1iZXJDdGwsIE11bHRp WGFjdElkVG9NZW1iZXJQYWdlKG5ld09sZGVzdE9mZnNldCkpKQ0KKwkgKiB7DQorCSAqICAgICAv LyBXQUwgbG9nIHRydW5jYXRpb24NCisJICogICAgIFdyaXRlTVRydW5jYXRlWGxvZ1JlYyhuZXdP bGRlc3RNdWx0aURCLCBuZXdPbGRlc3RNdWx0aSwgbmV3T2xkZXN0T2Zmc2V0KTsNCisJICogICAg IC8vIHVwZGF0ZSBpbiBhcnJheSBsaW1pdHMsIGV0Yy4NCisJICogICAgIC8vIHBlcmZvcm0gcGh5 c2ljYWwgdHJ1bmNhdGlvbg0KKwkgKiB9DQorCSAqLw0KIA0KIAkvKg0KIAkgKiBVcGRhdGUgaW4t bWVtb3J5IGxpbWl0cyBiZWZvcmUgcGVyZm9ybWluZyB0aGUgdHJ1bmNhdGlvbiwgd2hpbGUgaW5z aWRlDQotLSANCjIuMzQuMQ0K --0000000000004be1d2064d2672a9--