Re: Recovering from detoast-related catcache invalidations
Heikki Linnakangas <hlinnaka@iki.fi>
From: Heikki Linnakangas <hlinnaka@iki.fi>
To: Noah Misch <noah@leadboat.com>
Cc: Tom Lane <tgl@sss.pgh.pa.us>, Xiaoran Wang <fanfuxiaoran@gmail.com>,
pgsql-hackers@lists.postgresql.org, Andres Freund <andres@anarazel.de>
Date: 2025-01-09T09:39:53Z
Lists: pgsql-hackers
Commits
Same data as JSON:
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Fix catcache invalidation of a list entry that's being built
- f217c410553d 13.19 landed
- 91fc447c21d3 16.7 landed
- 96e61b2792a5 17.3 landed
- fce17c3a53d6 14.16 landed
- ce7c406f0f8d 15.11 landed
- af8cd1639ab2 18.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
-
Add previous commit to .git-blame-ignore-revs.
- 36578fa04942 17.0 landed
-
Re-pgindent catcache.c after previous commit.
- d41358f4bbc8 15.6 landed
- d29a4fbacfb7 12.18 landed
- 96c019ffa3f8 17.0 landed
- 7ceeb57baddd 14.11 landed
- 56dcd71decb7 16.2 landed
- 475b3ea3c06b 13.14 landed
-
Cope with catcache entries becoming stale during detoasting.
- db122d426a2d 14.11 landed
- ad98fb14226a 17.0 landed
- 98e03f957436 13.14 landed
- 7e2561e1a258 16.2 landed
- 3b4d85cf159c 12.18 landed
- 2a46a0df4793 15.6 landed
Attachments
- v3-0001-Fix-catcache-invalidation-of-a-list-entry-that-s-.patch (text/x-patch) patch v3-0001
On 07/01/2025 23:56, Noah Misch wrote:
> On Tue, Dec 24, 2024 at 12:18:09AM +0200, Heikki Linnakangas wrote:
>> I'm thinking of the attached to fix this. It changes the strategy for
>> detecting concurrent cache invalidations. Instead of the "recheck" mechanism
>> that was introduced in commit ad98fb1422, keep a stack of "build
>> in-progress" entries, and CatCacheInvalidate() invalidate those
>> "in-progress" entries in addition to the actual CatCTup and CatCList
>> entries.
>>
>> My first attempt was to insert the CatCTup or CatCList entry to the catcache
>> before starting to build it, marked with a flag to indicate that the entry
>> isn't fully built yet. But when I started to write that it got pretty
>> invasive, and it felt easier to add another structure to hold the
>> in-progress entries instead.
>
> That's similar to how relcache has been doing it (in_progress_list). I see no
> problem applying that technique here.
Oh thanks, I didn't notice that in relcache.c. I adjusted the naming and
comments in the new catcache.c code to be a little closer to the
relcache.c version, just to make it a bit more consistent.
The main difference is that relcache.c uses an array and an end-of-xact
callback to reset the array on error, while my implementation uses a
linked list of entries allocated on stack and PG_TRY-CATCH for error
cleanup. I considered adopting relcache.c's approach for the sake of
consistency, but decided to keep my original approach in the end. Some
of the code in catcache.c already had a suitable PG_TRY-CATCH block and
I didn't want to add a new end-of-xact callback just for this.
>> not sure I want to
>> commit the test with the injection point, but it's useful now to demonstrate
>> the bug.)
>
> I'd err on the side of including it. Apart from some copied comments, the
> test looks ready.
Ok, I cleaned up the comments.
> On Wed, Dec 25, 2024 at 11:27:38AM +0200, Heikki Linnakangas wrote:
>> +++ b/src/test/modules/test_misc/t/007_bugs.pl
>
> test_misc/t/007_bugs.pl could be home to almost anything. How about naming it
> 007_catcache_inval.pl?
Renamed
>> @@ -744,6 +770,13 @@ ResetCatalogCache(CatCache *cache)
>> #endif
>> }
>> }
>> +
>> + /* Also invalidate any entries that are being built */
>> + for (CatCCreating *e = catcache_creating_stack; e != NULL; e = e->next)
>> + {
>> + if (e->cache == cache)
>> + e->dead = true;
>> + }
>> }
>
> With debug_discard_caches=1, "make check" hangs early with some INSERT using
> 100% CPU. The new test file does likewise. I bet this needs a special case
> to short-circuit debug_discard_caches, like RelationCacheInvalidate() has.
Added
>> @@ -1665,6 +1698,8 @@ SearchCatCacheList(CatCache *cache,
>> HeapTuple ntp;
>> MemoryContext oldcxt;
>> int i;
>> + volatile CatCCreating creating_list;
>
> You could drop the volatile by copying catcache_creating_stack to an
> additional var that you reference after longjmp, instead of referencing
> creating_list.next after longjmp. Likewise for the instance of volatile in
> CatalogCacheCreateEntry().
> https://pubs.opengroup.org/onlinepubs/9799919799/functions/longjmp.html has
> the rules. Using volatile is fine, though.
Thanks for the tips. I used the additional var, it seems a little nicer.
>> + bool first_iter = true;
>
> This is okay as non-volatile, but it could just as easily move inside the
> PG_TRY.
Done
>> @@ -2076,38 +2118,33 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, SysScanDesc scandesc,
>
>> + PG_TRY();
>> {
>> - matches = equalTuple(before, ntp);
>> - heap_freetuple(before);
>> + dtp = toast_flatten_tuple(ntp, cache->cc_tupdesc);
>
> gcc 4.8.5 warns:
>
> catcache.c: In function ‘CatalogCacheCreateEntry’:
> catcache.c:2159:29: warning: ‘dtp’ may be used uninitialized in this function [-Wmaybe-uninitialized]
> ct->tuple.t_tableOid = dtp->t_tableOid;
>
> I remember some commit of a gcc 4.x warning fix in a recent year, and we do
> have buildfarm representation. Consider silencing it.
Hmm, I guess the compiler doesn't see that it's initialized with all the
PG_TRY()/CATCH() stuff. I initialized it to NULL to silence the warning.
Review of this new version is much appreciated, but if I don't hear
anything I'll commit and backpatch this.
--
Heikki Linnakangas
Neon (https://neon.tech)