1
0
mirror of https://github.com/postgres/postgres.git synced 2025-12-19 17:02:53 +03:00

For inplace update, send nontransactional invalidations.

The inplace update survives ROLLBACK.  The inval didn't, so another
backend's DDL could then update the row without incorporating the
inplace update.  In the test this fixes, a mix of CREATE INDEX and ALTER
TABLE resulted in a table with an index, yet relhasindex=f.  That is a
source of index corruption.

Back-patch to v14 - v17.  This is a back-patch of commits:

- 243e9b40f1
  (main change, on master, before v18 branched)
- 0bada39c83
  (defect fix, on master, before v18 branched)
- bae8ca82fd
  (cosmetics from post-commit review, on REL_18_STABLE)

It reverses commit c1099dd745, my revert
of the original back-patch of 243e9b4.

This back-patch omits the non-comment heap_decode() changes.  I find
those changes removed harmless code that was last necessary in v13.  See
discussion thread for details.  The back branches aren't the place to
remove such code.

Like the original back-patch, this doesn't change WAL, because these
branches use end-of-recovery SIResetAll().  All branches change the ABI
of extern function PrepareToInvalidateCacheTuple().  No PGXN extension
calls that, and there's no apparent use case in extensions.  Expect
".abi-compliance-history" edits to follow.

Reviewed-by: Paul A Jungwirth <pj@illuminatedcomputing.com>
Reviewed-by: Surya Poondla <s_poondla@apple.com>
Reviewed-by: Ilyasov Ian <ianilyasov@outlook.com>
Reviewed-by: Nitin Motiani <nitinmotiani@google.com> (in earlier versions)
Reviewed-by: Andres Freund <andres@anarazel.de> (in earlier versions)
Discussion: https://postgr.es/m/20240523000548.58.nmisch@google.com
Backpatch-through: 14-17
This commit is contained in:
Noah Misch
2025-12-16 16:13:54 -08:00
parent ed75434c45
commit 1d7b02711f
13 changed files with 364 additions and 128 deletions

View File

@@ -1337,14 +1337,24 @@ RecordTransactionCommit(void)
/*
* Transactions without an assigned xid can contain invalidation
* messages (e.g. explicit relcache invalidations or catcache
* invalidations for inplace updates); standbys need to process those.
* We can't emit a commit record without an xid, and we don't want to
* force assigning an xid, because that'd be problematic for e.g.
* vacuum. Hence we emit a bespoke record for the invalidations. We
* don't want to use that in case a commit record is emitted, so they
* happen synchronously with commits (besides not wanting to emit more
* WAL records).
* messages. While inplace updates do this, this is not known to be
* necessary; see comment at inplace CacheInvalidateHeapTuple().
* Extensions might still rely on this capability, and standbys may
* need to process those invals. We can't emit a commit record
* without an xid, and we don't want to force assigning an xid,
* because that'd be problematic for e.g. vacuum. Hence we emit a
* bespoke record for the invalidations. We don't want to use that in
* case a commit record is emitted, so they happen synchronously with
* commits (besides not wanting to emit more WAL records).
*
* XXX Every known use of this capability is a defect. Since an XID
* isn't controlling visibility of the change that prompted invals,
* other sessions need the inval even if this transactions aborts.
*
* ON COMMIT DELETE ROWS does a nontransactional index_build(), which
* queues a relcache inval, including in transactions without an xid
* that had read the (empty) table. Standbys don't need any ON COMMIT
* DELETE ROWS invals, but we've not done the work to withhold them.
*/
if (nmsgs != 0)
{