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

Revisit cosmetics of "For inplace update, send nontransactional invalidations."

This removes a never-used CacheInvalidateHeapTupleInplace() parameter.
It adds README content about inplace update visibility in logical
decoding.  It rewrites other comments.

Back-patch to v18, where commit 243e9b40f1
first appeared.  Since this removes a CacheInvalidateHeapTupleInplace()
parameter, expect a v18 ".abi-compliance-history" edit to follow.  PGXN
contains no calls to that function.

Reported-by: Paul A Jungwirth <pj@illuminatedcomputing.com>
Reported-by: Ilyasov Ian <ianilyasov@outlook.com>
Reviewed-by: Paul A Jungwirth <pj@illuminatedcomputing.com>
Reviewed-by: Surya Poondla <s_poondla@apple.com>
Discussion: https://postgr.es/m/CA+renyU+LGLvCqS0=fHit-N1J-2=2_mPK97AQxvcfKm+F-DxJA@mail.gmail.com
Backpatch-through: 18
This commit is contained in:
Noah Misch
2025-12-15 12:19:49 -08:00
parent 0839fbe400
commit 64bf53dd61
5 changed files with 57 additions and 33 deletions

View File

@@ -199,3 +199,35 @@ under a reader holding a pin. A reader of a heap_fetch() result tuple may
witness a torn read. Current inplace-updated fields are aligned and are no
wider than four bytes, and current readers don't need consistency across
fields. Hence, they get by with just fetching each field once.
During logical decoding, caches reflect an inplace update no later than the
next XLOG_XACT_INVALIDATIONS. That record witnesses the end of a command.
Tuples of its cmin are then visible to decoding, as are inplace updates of any
lower LSN. Inplace updates of a higher LSN may also be visible, even if those
updates would have been invisible to a non-historic snapshot matching
decoding's historic snapshot. (In other words, decoding may see inplace
updates that were not visible to a similar snapshot taken during original
transaction processing.) That's a consequence of inplace update violating
MVCC: there are no snapshot-specific versions of inplace-updated values. This
all makes it hard to reason about inplace-updated column reads during logical
decoding, but the behavior does suffice for relhasindex. A relhasindex=t in
CREATE INDEX becomes visible no later than the new pg_index row. While it may
be visible earlier, that's harmless. Finding zero indexes despite
relhasindex=t is normal in more cases than this, e.g. after DROP INDEX.
Example of a case that meaningfully reacts to the inplace inval:
CREATE TABLE cat (c int) WITH (user_catalog_table = true);
CREATE TABLE normal (d int);
...
CREATE INDEX ON cat (c)\; INSERT INTO normal VALUES (1);
If the output plugin reads "cat" during decoding of the INSERT, it's fair to
want that read to see relhasindex=t and use the new index.
An alternative would be to have decoding of XLOG_HEAP_INPLACE immediately
execute its invals. That would behave more like invals during original
transaction processing. It would remove the decoding-specific delay in e.g. a
decoding plugin witnessing a relfrozenxid change. However, a good use case
for that is unlikely, since the plugin would still witness relfrozenxid
changes prematurely. Hence, inplace update takes the trivial approach of
delegating to XLOG_XACT_INVALIDATIONS.