aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/misc/injection_point.c
Commit message (Collapse)AuthorAge
* Add support for runtime arguments in injection pointsMichael Paquier10 days
| | | | | | | | | | | | | | | | | | | The macros INJECTION_POINT() and INJECTION_POINT_CACHED() are extended with an optional argument that can be passed down to the callback attached when an injection point is run, giving to callbacks the possibility to manipulate a stack state given by the caller. The existing callbacks in modules injection_points and test_aio have their declarations adjusted based on that. da7226993fd4 (core AIO infrastructure) and 93bc3d75d8e1 (test_aio) and been relying on a set of workarounds where a static variable called pgaio_inj_cur_handle is used as runtime argument in the injection point callbacks used by the AIO tests, in combination with a TRY/CATCH block to reset the argument value. The infrastructure introduced in this commit will be reused for the AIO tests, simplifying them. Reviewed-by: Greg Burd <greg@burd.me> Discussion: https://postgr.es/m/Z_y9TtnXubvYAApS@paquier.xyz
* Update copyright for 2025Bruce Momjian2025-01-01
| | | | Backpatch-through: 13
* Fix comment in injection_point.cMichael Paquier2024-11-13
| | | | | | | | | | InjectionPointEntry->name was described as a hash key, which was fine when introduced in d86d20f0ba79, but it is not now. Oversight in 86db52a5062a, that has changed the way injection points are stored in shared memory from a hash table to an array. Backpatch-through: 17
* Remove unused #include's from backend .c filesPeter Eisentraut2024-10-27
| | | | | | | | as determined by IWYU These are mostly issues that are new since commit dbbca2cf299. Discussion: https://www.postgresql.org/message-id/flat/0df1d5b1-8ca8-4f84-93be-121081bde049%40eisentraut.org
* Fix attach of a previously-detached injection point.Noah Misch2024-08-22
| | | | | | | It's normal for the name in a free slot to match the new name. The max_inuse mechanism kept simple cases from reaching the problem. The problem could appear when index 0 was the previously-detached entry and index 1 is in use. Back-patch to v17, where this code first appeared.
* Add test for early backend startup errorsHeikki Linnakangas2024-07-26
| | | | | | | | | | | | | | | | The new test tests the libpq fallback behavior on an early error, which was fixed in the previous commit. This adds an IS_INJECTION_POINT_ATTACHED() macro, to allow writing injected test code alongside the normal source code. In principle, the new test could've been implemented by an extra test module with a callback that sets the FrontendProtocol global variable, but I think it's more clear to have the test code right where the injection point is, because it has pretty intimate knowledge of the surrounding context it runs in. Reviewed-by: Michael Paquier Discussion: https://www.postgresql.org/message-id/CAOYmi%2Bnwvu21mJ4DYKUa98HdfM_KZJi7B1MhyXtnsyOO-PB6Ww%40mail.gmail.com
* Fix using injection points at backend startup in EXEC_BACKEND modeHeikki Linnakangas2024-07-26
| | | | | | | | | | | | Commit 86db52a506 changed the locking of injection points to use only atomic ops and spinlocks, to make it possible to define injection points in processes that don't have a PGPROC entry (yet). However, it didn't work in EXEC_BACKEND mode, because the pointer to shared memory area was not initialized until the process "attaches" to all the shared memory structs. To fix, pass the pointer to the child process along with other global variables that need to be set up early. Backpatch-through: 17
* Add INJECTION_POINT_CACHED() to run injection points directly from cacheMichael Paquier2024-07-18
| | | | | | | | | | | | | | | | | | | | | | This new macro is able to perform a direct lookup from the local cache of injection points (refreshed each time a point is loaded or run), without touching the shared memory state of injection points at all. This works in combination with INJECTION_POINT_LOAD(), and it is better than INJECTION_POINT() in a critical section due to the fact that it would avoid all memory allocations should a concurrent detach happen since a LOAD(), as it retrieves a callback from the backend-private memory. The documentation is updated to describe in more details how to use this new macro with a load. Some tests are added to the module injection_points based on a new SQL function that acts as a wrapper of INJECTION_POINT_CACHED(). Based on a suggestion from Heikki Linnakangas. Author: Heikki Linnakangas, Michael Paquier Discussion: https://postgr.es/m/58d588d0-e63f-432f-9181-bed29313dece@iki.fi
* Use atomics to avoid locking in InjectionPointRun()Heikki Linnakangas2024-07-15
| | | | | | | | | | This allows using injection points without having a PGPROC, like early at backend startup, or in the postmaster. The injection points facility is new in v17, so backpatch there. Reviewed-by: Michael Paquier <michael@paquier.xyz> Disussion: https://www.postgresql.org/message-id/4317a7f7-8d24-435e-9e49-29b72a3dc418@iki.fi
* Support loading of injection pointsMichael Paquier2024-07-05
| | | | | | | | | | | | | | | | | | | This can be used to load an injection point and prewarm the backend-level cache before running it, to avoid issues if the point cannot be loaded due to restrictions in the code path where it would be run, like a critical section where no memory allocation can happen (load_external_function() can do allocations when expanding a library name). Tests can use a macro called INJECTION_POINT_LOAD() to load an injection point. The test module injection_points gains some tests, and a SQL function able to load an injection point. Based on a request from Andrey Borodin, who has implemented a test for multixacts requiring this facility. Reviewed-by: Andrey Borodin Discussion: https://postgr.es/m/ZkrBE1e2q2wGvsoN@paquier.xyz
* Improve locking around InjectionPointRun()Michael Paquier2024-06-28
| | | | | | | | | | | | | | | | As coded, an injection point could be loaded into the local cache without the LWLock InjectionPointLock taken, hence a point detached and re-attached concurrently of a point running calling InjectionPointRun() may finish by loading a callback it did no set initially. Based on all the cases discussed until now on the lists, it is fine to delay the lock release until the callback is run, so let's do that. While on it, remove a useless LWLockRelease() called before an error in InjectionPointAttach(). Per discussion with Heikki Linnakangas and Noah Misch. Discussion: https://postgr.es/m/e1ffb822-054e-4006-ac06-50532767f75b@iki.fi
* Introduce private data area for injection pointsMichael Paquier2024-05-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This commit extends the backend-side infrastructure of injection points so as it becomes possible to register some input data when attaching a point. This private data can be registered with the function name and the library name of the callback when attaching a point, then it is given as input argument to the callback. This gives the possibility for modules to pass down custom data at runtime when attaching a point without managing that internally, in a manner consistent with the callback entry retrieved from the hash shmem table storing the injection point data. InjectionPointAttach() gains two arguments, to be able to define the private data contents and its size. A follow-up commit will rely on this infrastructure to close a race condition with the injection point detach in the module injection_points. While on it, this changes InjectionPointDetach() to return a boolean, returning false if a point cannot be detached. This has been mentioned by Noah as useful when it comes to implement more complex tests with concurrent point detach, solid with the automatic detach done for local points in the test module. Documentation is adjusted in consequence. Per discussion with Noah Misch. Reviewed-by: Noah Misch Discussion: https://postgr.es/m/20240509031553.47@rfd.leadboat.com
* Fix ERROR message in injection_point.cMichael Paquier2024-01-23
| | | | | | | | | | | | This commit fixes an error message that failed to show the correct function and library names when a function cannot be loaded. While on it, adjust the call to load_external_function() so as this ERROR can be reached, by making load_external_function() return NULL rather than fail if a function cannot be found for a given injection point. Thinkos in d86d20f0ba79.
* Fix two memcpy() bugs in the new injection point codeHeikki Linnakangas2024-01-22
| | | | | | | | | | | | | | 1. The memcpy()s in InjectionPointAttach() would copy garbage from beyond the end of input string to the buffer in shared memory. You won't usually notice, but if there is not enough valid mapped memory beyond the end of the string, the read of unmapped memory will segfault. This was flagged by the Cirrus CI build with address sanitizer enabled. 2. The memcpy() in injection_point_cache_add() failed to copy the NULL terminator. Discussion: https://www.postgresql.org/message-id/0615a424-b726-4157-afa7-4245629f9512%40iki.fi
* Add backend support for injection pointsMichael Paquier2024-01-22
Injection points are a new facility that makes possible for developers to run custom code in pre-defined code paths. Its goal is to provide ways to design and run advanced tests, for cases like: - Race conditions, where processes need to do actions in a controlled ordered manner. - Forcing a state, like an ERROR, FATAL or even PANIC for OOM, to force recovery, etc. - Arbitrary sleeps. This implements some basics, and there are plans to extend it more in the future depending on what's required. Hence, this commit adds a set of routines in the backend that allows developers to attach, detach and run injection points: - A code path calling an injection point can be declared with the macro INJECTION_POINT(name). - InjectionPointAttach() and InjectionPointDetach() to respectively attach and detach a callback to/from an injection point. An injection point name is registered in a shmem hash table with a library name and a function name, which will be used to load the callback attached to an injection point when its code path is run. Injection point names are just strings, so as an injection point can be declared and run by out-of-core extensions and modules, with callbacks defined in external libraries. This facility is hidden behind a dedicated switch for ./configure and meson, disabled by default. Note that backends use a local cache to store callbacks already loaded, cleaning up their cache if a callback has found to be removed on a best-effort basis. This could be refined further but any tests but what we have here was fine with the tests I've written while implementing these backend APIs. Author: Michael Paquier, with doc suggestions from Ashutosh Bapat. Reviewed-by: Ashutosh Bapat, Nathan Bossart, Álvaro Herrera, Dilip Kumar, Amul Sul, Nazir Bilal Yavuz Discussion: https://postgr.es/m/ZTiV8tn_MIb_H2rE@paquier.xyz