Re: Weird test mixup
Noah Misch <noah@leadboat.com>
From: Noah Misch <noah@leadboat.com>
To: Michael Paquier <michael@paquier.xyz>
Cc: Heikki Linnakangas <hlinnaka@iki.fi>, Tom Lane <tgl@sss.pgh.pa.us>, pgsql-hackers <pgsql-hackers@postgresql.org>
Date: 2024-05-09T03:15:53Z
Lists: pgsql-hackers
On Thu, May 09, 2024 at 09:37:54AM +0900, Michael Paquier wrote: > On Tue, May 07, 2024 at 11:53:10AM -0700, Noah Misch wrote: > > The problem I'm trying to tackle in this thread is to make > > src/test/modules/gin installcheck-safe. $SUBJECT's commit 5105c90 started > > that work, having seen the intarray test suite break when run concurrently > > with the injection_points test suite. That combination still does break at > > the exit-time race condition. To reproduce, apply this attachment to add > > sleeps, and run: > > > > make -C src/test/modules/gin installcheck USE_MODULE_DB=1 & sleep 2; make -C contrib/intarray installcheck USE_MODULE_DB=1 > > Thanks for that. I am not really sure how to protect that without a > small cost in flexibility for the cases of detach vs run paths. This > comes down to the fact that a custom routine could be run while it > could be detached concurrently, removing any stuff a callback could > depend on in the module. > > It was mentioned upthread to add to InjectionPointCacheEntry a fixed > area of memory that modules could use to store some "status" data, but > it would not close the run/detach race because a backend could still > hold a pointer to a callback, with concurrent backends playing with > the contents of InjectionPointCacheEntry (concurrent detaches and > attaches that would cause the same entries to be reused). > One way to close entirely the window would be to hold > InjectionPointLock longer in InjectionPointRun() until the callback > finishes or until it triggers an ERROR. This would mean that the case > you've mentioned in [1] would change, by blocking the detach() of s3 > until the callback of s2 finishes. > [1] https://www.postgresql.org/message-id/20240501231214.40@rfd.leadboat.com Yes, that would be a loss for test readability. Also, I wouldn't be surprised if some test will want to attach POINT-B while POINT-A is in injection_wait(). Various options avoiding those limitations: 1. The data area formerly called a "status" area is immutable after attach. The core code copies it into a stack buffer to pass in a const callback argument. 2. InjectionPointAttach() returns an attachment serial number, and the callback receives that as an argument. injection_points.c would maintain an InjectionPointCondition for every still-attached serial number, including global attachments. Finding no condition matching the serial number argument means detach already happened and callback should do nothing. 3. Move the PID check into core code. 4. Separate the concept of "make ineligible to fire" from "detach", with stronger locking for detach. v1 pointed in this direction, though not using that terminology. 5. Injection point has multiple callbacks. At least one runs with the lock held and can mutate the "status" data. At least one runs without the lock. (1) is, I think, simple and sufficient. How about that?
Commits
-
injection_points: Store runtime conditions in private area
- 267d41dc4f41 17.0 landed
-
Introduce private data area for injection points
- 33181b48fd0e 17.0 landed
-
injection_points: Fix incorrect spinlock acquisition
- 597f66942d0b 17.0 landed
-
Make GIN tests using injection points concurrent-safe
- 5105c9079681 17.0 landed
-
injection_points: Fix race condition with local injection point tests
- f4083c497510 17.0 landed
-
injection_points: Introduce runtime conditions
- f587338dec87 17.0 landed
-
Make GIN test using injection points repeatable
- 997db123c054 17.0 landed
-
Fix backstop in gin test if injection point is not reached
- d802ff06d021 17.0 landed
-
Try to unbreak injection-fault tests in the buildfarm
- 85f65d7a26fc 17.0 landed
-
Disable tests using injection points in installcheck
- e2e3b8ae9ed7 17.0 landed