Re: Inval reliability, especially for inplace updates
Noah Misch <noah@leadboat.com>
Commits
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Update .abi-compliance-history for PrepareToInvalidateCacheTuple().
- d88f4535d29f 15.16 landed
- a3e7bbd410d4 17.8 landed
- 2e58802f7332 14.21 landed
- 2655d2e47803 16.12 landed
-
Assert lack of hazardous buffer locks before possible catalog read.
- 0dfbd191a939 14.21 landed
- 86091202a8b1 15.16 landed
- 27e4fad9804c 16.12 landed
- bcb784e7d2f9 17.8 landed
- f4ece891fc2f 18.0 landed
-
For inplace update, send nontransactional invalidations.
- 811422471940 14.21 landed
- 1d7b02711f70 16.12 landed
- 05d605b6c69f 15.16 landed
- 0f69beddea11 17.8 landed
- 4cf948cbeedf 12.21 landed
- 0ea9d40a6679 13.17 landed
- e3914bd136e4 14.14 landed
- 4eac5a1fa78e 15.9 landed
- ce8c571d014e 16.5 landed
- 95c5acb3fc26 17.1 landed
- 243e9b40f1b2 18.0 landed
-
Update .abi-compliance-history for CacheInvalidateHeapTupleInplace().
- 06b030e8973f 18.2 landed
-
Revisit cosmetics of "For inplace update, send nontransactional invalidations."
- bae8ca82fd00 18.2 landed
- 64bf53dd61ea 19 (unreleased) landed
-
Correct comments of "Fix data loss at inplace update after heap_update()".
- 0839fbe400d7 19 (unreleased) landed
-
Move I/O before the index_update_stats() buffer lock region.
- d729f1ea5a46 12.21 landed
- 6b01cac0be6d 13.17 landed
- bb3054297661 14.14 landed
- 6d5b4031b927 15.9 landed
- 6c837c237bf8 16.5 landed
- 0bcb9d07940c 17.1 landed
- b412f402d1e0 18.0 landed
-
Revert "For inplace update, send nontransactional invalidations."
- 4b0f7d6c162e 12.21 landed
- fe8091c9e39e 13.17 landed
- 4c7088729503 14.14 landed
- 27642d89081e 15.9 landed
- 6f9dd2282e37 16.5 landed
- c1099dd745b0 17.1 landed
-
Revert "WAL-log inplace update before revealing it to other sessions."
- 5e503e10d13e 12.21 landed
- be74b943c920 13.17 landed
- 9a1c73636d60 14.14 landed
- e50f9de98d63 15.9 landed
- d5be10758b36 16.5 landed
- bc6bad885725 17.1 landed
-
Fix inplace update buffer self-deadlock.
- 0bada39c83a1 18.0 landed
-
Remove duplicate words in comments
- fb7e27abfbd4 18.0 cited
-
At end of recovery, reset all sinval-managed caches.
- da9950456463 12.21 landed
- 67f30c79a1c1 13.17 landed
- dca68242a81b 14.14 landed
- 3baf804b7295 15.9 landed
- d36b4d8ec322 16.5 landed
- a4668c99f0f8 17.1 landed
-
Fix data loss at inplace update after heap_update().
- a07e03fd8fa7 18.0 cited
-
Remove comment about xl_heap_inplace "AT END OF STRUCT".
- c63ceb2f0006 13.16 landed
- 77d0bc8001e6 12.20 landed
- c7f10df36806 14.13 landed
- 2ca8ca4827af 15.8 landed
- e352ba7b7509 16.4 landed
- 4a7f91b3d314 17.0 landed
-
Reduce memory consumption for pending invalidation messages.
- 3aafc030a536 15.0 cited
-
Add support for streaming to built-in logical replication.
- 464824323e57 14.0 cited
-
WAL Log invalidations at command end with wal_level=logical.
- c55040ccd017 14.0 cited
-
Introduce logical decoding.
- b89e151054a0 9.4.0 cited
-
Rename and document some invalidation routines to make it clearer that
- 81d08fcffeed 7.1.1 cited
On Thu, Oct 31, 2024 at 01:01:39PM -0700, Noah Misch wrote:
> On Thu, Oct 31, 2024 at 05:00:02PM +0300, Alexander Lakhin wrote:
> > I've accidentally discovered an incorrect behaviour caused by commit
> > 4eac5a1fa. Running this script:
>
> Thanks. This looks important.
>
> > parallel -j40 --linebuffer --tag .../reproi.sh ::: `seq 40`
>
> This didn't reproduce it for me, at -j20, -j40, or -j80. I tested at commit
> fb7e27a. At what commit(s) does it reproduce for you? At what commits, if
> any, did your test not reproduce this?
I reproduced this using a tmpfs current working directory.
> > All three autovacuum workers (1143263, 1143320, 1143403) are also waiting
> > for the same buffer lock:
> > #5 0x0000561dd715f1fe in PGSemaphoreLock (sema=0x7fed9a817338) at pg_sema.c:327
> > #6 0x0000561dd722fe02 in LWLockAcquire (lock=0x7fed9ad9b4e4, mode=LW_SHARED) at lwlock.c:1318
> > #7 0x0000561dd71f8423 in LockBuffer (buffer=36, mode=1) at bufmgr.c:4182
>
> Can you share the full backtrace for the autovacuum workers?
Here, one of the autovacuum workers had the guilty stack trace, appearing at
the end of this message. heap_inplace_update_and_unlock() calls
CacheInvalidateHeapTupleInplace() while holding BUFFER_LOCK_EXCLUSIVE on a
buffer of pg_class. CacheInvalidateHeapTupleInplace() may call
CatalogCacheInitializeCache(), which opens the cache's rel. If there's not a
valid relcache entry for the catcache's rel, we scan pg_class to make a valid
relcache entry. The ensuing hang makes sense.
Tomorrow, I'll think more about fixes. Two that might work:
1. Call CacheInvalidateHeapTupleInplace() before locking the buffer. Each
time we need to re-find the tuple, discard the previous try's inplace
invals and redo CacheInvalidateHeapTupleInplace(). That's because
concurrent activity may have changed cache key fields like relname.
2. Add some function that we call before locking the buffer. Its charter is
to ensure PrepareToInvalidateCacheTuple() won't have to call
CatalogCacheInitializeCache(). I think nothing resets catcache to the
extent that CatalogCacheInitializeCache() must happen again, so this should
suffice regardless of concurrent sinval traffic, debug_discard_caches, etc.
What else is worth considering? Any preferences among those?
#6 0x0000555e8a3c3afc in LWLockAcquire (lock=0x7f1683a65424, mode=LW_SHARED) at lwlock.c:1287
#7 0x0000555e8a08cec8 in heap_prepare_pagescan (sscan=sscan@entry=0x7f168e99ba48) at heapam.c:512
#8 0x0000555e8a08d6f1 in heapgettup_pagemode (scan=scan@entry=0x7f168e99ba48, dir=<optimized out>, nkeys=<optimized out>, key=<optimized out>) at heapam.c:979
#9 0x0000555e8a08dc9e in heap_getnextslot (sscan=0x7f168e99ba48, direction=<optimized out>, slot=0x7f168e9a58c0) at heapam.c:1299
#10 0x0000555e8a0aad3d in table_scan_getnextslot (direction=ForwardScanDirection, slot=<optimized out>, sscan=<optimized out>)
at ../../../../src/include/access/tableam.h:1080
#11 systable_getnext (sysscan=sysscan@entry=0x7f168e9a79c8) at genam.c:538
#12 0x0000555e8a501391 in ScanPgRelation (targetRelId=<optimized out>, indexOK=false, force_non_historic=force_non_historic@entry=false) at relcache.c:388
#13 0x0000555e8a507ea4 in RelationReloadIndexInfo (relation=0x7f168f1b8808) at relcache.c:2272
#14 RelationRebuildRelation (relation=0x7f168f1b8808) at relcache.c:2573
#15 0x0000555e8a5083e5 in RelationFlushRelation (relation=0x7f168f1b8808) at relcache.c:2848
#16 RelationCacheInvalidateEntry (relationId=<optimized out>) at relcache.c:2910
#17 0x0000555e8a4fafaf in LocalExecuteInvalidationMessage (msg=0x7ffec99ff8a0) at inval.c:795
#18 0x0000555e8a3b711a in ReceiveSharedInvalidMessages (invalFunction=invalFunction@entry=0x555e8a4faf10 <LocalExecuteInvalidationMessage>,
resetFunction=resetFunction@entry=0x555e8a4fa650 <InvalidateSystemCaches>) at sinval.c:88
#19 0x0000555e8a4fa677 in AcceptInvalidationMessages () at inval.c:865
#20 0x0000555e8a3bc809 in LockRelationOid (relid=1259, lockmode=1) at lmgr.c:135
#21 0x0000555e8a05155d in relation_open (relationId=relationId@entry=1259, lockmode=lockmode@entry=1) at relation.c:55
#22 0x0000555e8a0dd809 in table_open (relationId=relationId@entry=1259, lockmode=lockmode@entry=1) at table.c:44
#23 0x0000555e8a501359 in ScanPgRelation (targetRelId=<optimized out>, indexOK=indexOK@entry=true, force_non_historic=force_non_historic@entry=false)
at relcache.c:371
#24 0x0000555e8a507f9a in RelationReloadNailed (relation=0x7f168f1738c8) at relcache.c:2380
#25 RelationRebuildRelation (relation=0x7f168f1738c8) at relcache.c:2579
#26 0x0000555e8a5083e5 in RelationFlushRelation (relation=0x7f168f1738c8) at relcache.c:2848
#27 RelationCacheInvalidateEntry (relationId=<optimized out>) at relcache.c:2910
#28 0x0000555e8a4fafaf in LocalExecuteInvalidationMessage (msg=0x7ffec99ffc80) at inval.c:795
#29 0x0000555e8a3b71aa in ReceiveSharedInvalidMessages (invalFunction=invalFunction@entry=0x555e8a4faf10 <LocalExecuteInvalidationMessage>,
resetFunction=resetFunction@entry=0x555e8a4fa650 <InvalidateSystemCaches>) at sinval.c:118
#30 0x0000555e8a4fa677 in AcceptInvalidationMessages () at inval.c:865
#31 0x0000555e8a3bc809 in LockRelationOid (relid=1259, lockmode=1) at lmgr.c:135
#32 0x0000555e8a05155d in relation_open (relationId=1259, lockmode=lockmode@entry=1) at relation.c:55
#33 0x0000555e8a0dd809 in table_open (relationId=<optimized out>, lockmode=lockmode@entry=1) at table.c:44
#34 0x0000555e8a4f7211 in CatalogCacheInitializeCache (cache=cache@entry=0x555eb26d2180) at catcache.c:1045
#35 0x0000555e8a4f9a68 in PrepareToInvalidateCacheTuple (relation=relation@entry=0x7f168f1738c8, tuple=tuple@entry=0x7f168e9a74e8, newtuple=newtuple@entry=0x0,
function=function@entry=0x555e8a4fa220 <RegisterCatcacheInvalidation>, context=context@entry=0x7f168e9a7428) at catcache.c:2326
#36 0x0000555e8a4fa500 in CacheInvalidateHeapTupleCommon (relation=relation@entry=0x7f168f1738c8, tuple=tuple@entry=0x7f168e9a74e8, newtuple=newtuple@entry=0x0,
prepare_callback=prepare_callback@entry=0x555e8a4fa320 <PrepareInplaceInvalidationState>) at inval.c:1391
#37 0x0000555e8a4fabcb in CacheInvalidateHeapTupleCommon (prepare_callback=0x555e8a4fa320 <PrepareInplaceInvalidationState>, newtuple=newtuple@entry=0x0,
tuple=tuple@entry=0x7f168e9a74e8, relation=relation@entry=0x7f168f1738c8) at inval.c:1504
#38 0x0000555e8a094f7c in heap_inplace_update_and_unlock (relation=0x7f168f1738c8, oldtup=0x555eb277ea58, tuple=0x7f168e9a74e8, buffer=3) at heapam.c:6354
#39 0x0000555e8a0ab35a in systable_inplace_update_finish (state=0x7f168e9a72c8, tuple=<optimized out>) at genam.c:891
#40 0x0000555e8a1fbdc4 in vac_update_relstats (relation=relation@entry=0x7f168f1beae8, num_pages=num_pages@entry=19, num_tuples=<optimized out>,
num_all_visible_pages=<optimized out>, hasindex=hasindex@entry=true, frozenxid=frozenxid@entry=0, minmulti=minmulti@entry=0, frozenxid_updated=0x0,
minmulti_updated=0x0, in_outer_xact=false) at vacuum.c:1545
#41 0x0000555e8a18c97c in do_analyze_rel (onerel=onerel@entry=0x7f168f1beae8, params=params@entry=0x555eb272e2e4, va_cols=va_cols@entry=0x0,
acquirefunc=<optimized out>, relpages=19, inh=inh@entry=false, in_outer_xact=false, elevel=13) at analyze.c:643
#42 0x0000555e8a18e122 in analyze_rel (relid=<optimized out>, relation=<optimized out>, params=params@entry=0x555eb272e2e4, va_cols=0x0,
in_outer_xact=<optimized out>, bstrategy=bstrategy@entry=0x555eb2741238) at analyze.c:249
#43 0x0000555e8a1fc883 in vacuum (relations=0x555eb274b370, relations@entry=0x555eb2749390, params=params@entry=0x555eb272e2e4,
bstrategy=bstrategy@entry=0x555eb2741238, vac_context=vac_context@entry=0x555eb274b220, isTopLevel=isTopLevel@entry=true) at vacuum.c:635
#44 0x0000555e8a330e69 in autovacuum_do_vac_analyze (bstrategy=<optimized out>, tab=<optimized out>) at autovacuum.c:3108
#45 do_autovacuum () at autovacuum.c:2425
#46 0x0000555e8a33132f in AutoVacWorkerMain (startup_data=<optimized out>, startup_data_len=<optimized out>) at autovacuum.c:1571
...
(gdb) p num_held_lwlocks
$2 = 1