Re: race condition in pg_class
Nitin Motiani <nitinmotiani@google.com>
Commits
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Replace tests of ALTER DATABASE RESET TABLESPACE.
- 4adb0380b9bf 19 (unreleased) landed
-
meson: Flush stdout in testwrap
- d9bc60705274 16.9 landed
- 9de86e367a67 17.5 landed
- 5941946d0934 18.0 landed
-
Fix catcache invalidation of a list entry that's being built
- af8cd1639ab2 18.0 cited
-
Stop reading uninitialized memory in heap_inplace_lock().
- a0c0078b1355 12.21 landed
- ad24b7565910 14.14 landed
- 3e5ea478d875 13.17 landed
- d34ffbaa1029 15.9 landed
- 2d63c964f010 16.5 landed
- e11907682846 17.1 landed
- e947224cbbce 18.0 landed
-
Fix use of uninitialized value in previous commit.
- 0cf3d41cbb42 15.9 landed
- 90f5412a9a51 16.5 landed
-
Back-patch "Refactor code in tablecmds.c to check and process tablespace moves"
- dc845383cd12 12.21 landed
- 1299564cb9c7 13.17 landed
-
Fix data loss at inplace update after heap_update().
- 7354b680ab64 12.21 landed
- a8ad1929d2ec 13.17 landed
- 8590c942c1a6 15.9 landed
- 82c2d9e02206 14.14 landed
- 63f01980560a 16.5 landed
- fd27b878c2ea 17.1 landed
- a07e03fd8fa7 18.0 landed
-
For inplace update durability, make heap_update() callers wait.
- cafcc3ad0ed3 12.21 landed
- 14c57cb63907 13.17 landed
- f51b34b3eddb 14.14 landed
- 5c837f8fa022 15.9 landed
- 51ff46de29f6 16.5 landed
- 3b7a689e1a80 17.1 landed
- aac2c9b4fde8 18.0 landed
-
Warn if LOCKTAG_TUPLE is held at commit, under debug_assertions.
- b779d37a3db2 12.21 landed
- 5ef9b4a2f796 13.17 landed
- c9de1b8ac8df 14.14 landed
- 41e0ba33d5ab 15.9 landed
- acc63ef4fbe6 16.5 landed
- f33bf1c7d501 17.1 landed
- dbf3f974ee04 18.0 landed
-
Don't lose partitioned table reltuples=0 after relhassubclass=f.
- e81deeefcac2 16.4 landed
- 2b4a2a79edd2 15.8 landed
- 2b415e95a8a7 14.13 landed
- f5bb46fb2e65 17.0 landed
- 7102070329d8 18.0 landed
-
Fix new assertion for MERGE view_name ... DO NOTHING.
- 0d3b35c367c2 17.0 landed
- d5e6891502ca 18.0 landed
-
Remove configuration-dependent output from new inplace-inval test.
- 79567599cd21 12.20 landed
- f31c1e34bc80 14.13 landed
- ca30e8ba958a 13.16 landed
- 7857c8dc4481 16.4 landed
- 458fada72b32 15.8 landed
- b99414de9052 17.0 landed
-
AccessExclusiveLock new relations just after assigning the OID.
- 7af775bbae57 12.20 landed
- e038b7756df8 14.13 landed
- b899cde0b86a 13.16 landed
- 0f2835ea6fc1 15.8 landed
- fc8c25806e84 16.4 landed
- 5b823b179e5e 17.0 landed
-
Cope with inplace update making catcache stale during TOAST fetch.
- 7a21306aee0a 13.16 landed
- 11f3815d6af8 12.20 landed
- af73e37fa181 14.13 landed
- b08a4b6163eb 15.8 landed
- e4afd7153bd8 16.4 landed
- f9f47f0d93d1 17.0 landed
-
Expand comments and add an assertion in nodeModifyTable.c.
- fea47de3016a 12.20 landed
- c3437fb7255b 13.16 landed
- ad4653268c12 14.13 landed
- f0544432c3cc 15.8 landed
- f8135d8b54ff 16.4 landed
- d5f788b41dc2 17.0 landed
-
Improve test coverage for changes to inplace-updated catalogs.
- 796d191028bb 12.20 landed
- 65aae93c456a 13.16 landed
- 2d06bdbc0cc3 14.13 landed
- 3c6becd3d180 15.8 landed
- dd8008e8ec95 16.4 landed
- 0844b3968985 17.0 landed
-
Lock before setting relhassubclass on RELKIND_PARTITIONED_INDEX.
- e2eefb97e31a 12.20 landed
- 1a6d65b64e84 13.16 landed
- 578db9c9257d 14.13 landed
- a338e41374e4 15.8 landed
- 480b58fabd35 16.4 landed
- 0cecc908e974 17.0 landed
-
Lock owned sequences during ALTER TABLE SET { LOGGED | UNLOGGED }.
- 24561b498f11 15.8 landed
- 112d055706bf 16.4 landed
- f88cdb36c457 17.0 landed
-
Make TAP todo_start effects the same under Meson and prove_check.
- 288426902ee5 16.4 landed
- 22a4b104ba70 17.0 landed
-
Add an injection_points isolation test suite.
- c35f419d6efb 17.0 landed
-
Add wait event type "InjectionPoint", a custom type like "Extension".
- bb93640a681c 17.0 landed
-
Create waitfuncs.c for pg_isolation_test_session_is_blocked().
- abfbd13af0e9 17.0 landed
-
Rework planning and execution of UPDATE and DELETE.
- 86dc90056dfd 14.0 cited
On Wed, Sep 4, 2024 at 2:53 AM Noah Misch <noah@leadboat.com> wrote:
>
>
> > So this also pulls the invalidation to the genam.c
> > layer. Am I understanding this correctly?
>
> Compared to the v9 patch, the "call both" alternative would just move the
> systable_endscan() call to a new systable_inplace_update_end(). It wouldn't
> move anything across the genam:heapam boundary.
> systable_inplace_update_finish() would remain a thin wrapper around a heapam
> function.
>
Thanks for the clarification.
> > > > > - Hoist the CacheInvalidateHeapTuple() up to the genam.c layer. While
> > > > > tolerable now, this gets less attractive after the inplace160 patch from
> > > > > https://postgr.es/m/flat/20240523000548.58.nmisch@google.com
> > > > >
> > > > I skimmed through the inplace160 patch. It wasn't clear to me why this
> > > > becomes less attractive with the patch. I see there is a new
> > > > CacheInvalidateHeapTupleInPlace but that looks like it would be called
> > > > while holding the lock. And then there is an
> > > > AcceptInvalidationMessages which can perhaps be moved to the genam.c
> > > > layer too. Is the concern that one invalidation call will be in the
> > > > heapam layer and the other will be in the genam layer?
> > >
> > > That, or a critical section would start in heapam.c, then end in genam.c.
> > > Current call tree at inplace160 v4:
>
> > How about this alternative?
> >
> > genam.c:systable_inplace_update_finish
> > PreInplace_Inval
> > START_CRIT_SECTION
> > heapam.c:heap_inplace_update
> > BUFFER_LOCK_UNLOCK
> > AtInplace_Inval
> > END_CRIT_SECTION
> > UnlockTuple
> > AcceptInvalidationMessages
>
> > Looking at inplace160, it seems that the start of the critical section
> > is right after PreInplace_Inval. So why not pull START_CRIT_SECTION
> > and END_CRIT_SECTION out to the genam.c layer?
>
> heap_inplace_update() has an elog(ERROR) that needs to happen outside any
> critical section. Since the condition for that elog deals with tuple header
> internals, it belongs at the heapam layer more than the systable layer.
>
Understood. How about this alternative then? The tuple length check
and the elog(ERROR) gets its own function. Something like
heap_inplace_update_validate or
heap_inplace_update_validate_tuple_length. So in that case, it would
look like this :
genam.c:systable_inplace_update_finish
heapam.c:heap_inplace_update_validate/heap_inplace_update_precheck
PreInplace_Inval
START_CRIT_SECTION
heapam.c:heap_inplace_update
BUFFER_LOCK_UNLOCK
AtInplace_Inval
END_CRIT_SECTION
UnlockTuple
AcceptInvalidationMessages
This is starting to get complicated though so I don't have any issues
with just renaming the heap_inplace_update to
heap_inplace_update_and_unlock.
> > Alternatively since
> > heap_inplace_update is commented as a subroutine of
> > systable_inplace_update_finish, should everything just be moved to the
> > genam.c layer? Although it looks like you already considered and
> > rejected this approach.
>
> Calling XLogInsert(RM_HEAP_ID) in genam.c would be a worse modularity
> violation than the one that led to the changes between v8 and v9. I think
> even calling CacheInvalidateHeapTuple() in genam.c would be a worse modularity
> violation than the one attributed to v8. Modularity would have the
> heap_inplace function resemble heap_update() handling of invals.
>
Understood. Thanks.
> > If the above alternatives are not possible, it's probably fine to go
> > ahead with the current patch with the function renamed to
> > heap_inplace_update_and_unlock (or something similar) as mentioned
> > earlier?
>
> I like that name. The next version will use it.
>
So either we go with this or try the above approach of having a
separate function _validate/_precheck/_validate_tuple_length. I don't
have a strong opinion on either of these approaches.
> > > > I see that all the places we check resultRelInfo->ri_needLockTagTuple,
> > > > we can just call
> > > > IsInplaceUpdateRelation(resultRelInfo->ri_RelationDesc). Is there a
> > > > big advantage of storing a separate bool field? Also there is another
> > >
> > > No, not a big advantage. I felt it was more in line with the typical style of
> > > src/backend/executor.
>
> > just find it a smell that there are two fields which are not
> > independent and they go out of sync. And that's why my preference is
> > to not have a dependent field unless there is a specific advantage.
>
> Got it. This check happens for every tuple of every UPDATE, so performance
> may be a factor. Some designs and their merits:
>
Thanks. If performance is a factor, it makes sense to keep it.
> ==== a. ri_needLockTagTuple
> Performance: best: check one value for nonzero
> Drawback: one more value lifecycle to understand
> Drawback: users of ResultRelInfo w/o InitResultRelInfo() could miss this
>
> ==== b. call IsInplaceUpdateRelation
> Performance: worst: two extern function calls, then compare against two values
>
> ==== c. make IsInplaceUpdateRelation() and IsInplaceUpdateOid() inline, and call
> Performance: high: compare against two values
> Drawback: unlike catalog.c peers
> Drawback: extensions that call these must recompile if these change
>
> ==== d. add IsInplaceUpdateRelationInline() and IsInplaceUpdateOidInline(), and call
> Performance: high: compare against two values
> Drawback: more symbols to understand
> Drawback: extensions might call these, reaching the drawback of (c)
>
> I think my preference order is (a), (c), (d), (b). How do you see it?
>
My preference order would be the same. In general I like (c) more than
(a) but recompiling extensions sounds like a major drawback so here
the preference is (a).
Can we do (a) along with some extra checks? To elaborate, execMain.c
has a function called CheckValidateRelationRel which is called by
ExecInitModifyTable in nodeModifyTable.c. Can we add the following
assert assert (or just a debug assert) in this function?
Assert(rel->ri_needsLockTagTuple == IsInplaceUpdateRelation(rel->relationDesc)
This can safeguard against users of ResultRelInfo missing this field.
An alternative might be to only do debug assertions in the functions
which use the field. But it seems simpler to just do it once in the
ExecInitModifyTable.
> > But even for the
> > ri_TrigDesc, CatalogOpenIndexes() still sets it to NULL. So shouldn't
> > ri_needLockTagTuple also be set to a default value of false?
>
> CatalogOpenIndexes() explicitly zero-initializes two fields and relies on
> makeNode() zeroing for dozens of others. Hence, omitting the initialization
> fits the function's local convention better than including it. (PostgreSQL
> has no policy or dominant practice about redundant zero-initialization.)
Thanks. Makes sense.
Thanks & Regards
Nitin Motiani
Google