sql-info.de
May 18, 2022

PostgreSQL | Fini for _PG_fini(): recent changes in shared library coding

For many years the documentation has contained the following statement:

If the file includes a function named _PG_fini, that function will be called
immediately before unloading the file. Likewise, the function receives no
parameters and should return void. Note that _PG_fini will only be called
during an unload of the file, not during process termination. (Presently,
unloads are disabled and will never occur, but this may change in the
future.)

meaning all those instances of _PG_fini() dutifully included in shared library code have never actually done anything (see: src/backend/utils/fmgr/dfmgr.c).

We are now finally in that future, but it has been decided that the never-implemented idea of unloading shared librarie is offically abandoned, and _PG_fini() has been removed completely (commit ab02d702).

In practical terms this will have no effect on existing code containing _PG_fini(), and the code will compile and function as before. However as of PostgreSQL 15, any _PG_fini() function will be demoted from an effective no-op to a complete waste of space, so it can be removed entirely. For that matter it can just as well be removed from code meant to build against earlier PostgreSQL versions.

PostgreSQL 15: _PG_init() and shmem_request_hook

At the other end of the shared library load cycle, commit 4f2400cb brings an important change for any shared extensions which request additional  shared memory and LWLocks in _PG_init() - this must now be done via the new hook shmem_request_hook.

Assuming the shared library is intended to be compiled against multiple PostgreSQL versions (common in extensions which are not part of the core code), the modification required is something like this:

#if (PG_VERSION_NUM >= 150000)
static shmem_request_hook_type prev_shmem_request_hook = NULL;
static void ourextension_shmem_request(void);
#endif


static void
_PG_init()
{
/* ... */

#if (PG_VERSION_NUM >= 150000)
prev_shmem_request_hook = shmem_request_hook;
shmem_request_hook = ourextension_shmem_request;
#else
RequestAddinShmemSpace(MAXALIGN(sizeof(OurExtensionState)));
#endif

/* ... */
}

#if (PG_VERSION_NUM >= 150000)
/*
* Requests any additional shared memory required for our extension
*/
static void
ourextension_shmem_request(void)
{
if (prev_shmem_request_hook)
prev_shmem_request_hook();

RequestAddinShmemSpace(MAXALIGN(sizeof(OurExtensionSharedState)));
}
#endif

Code which still attempts to request shared memory in _PG_init() will cause server startup to abort with a FATAL error:

[2022-05-18 22:48:22 JST]    FATAL:  XX000: cannot request additional shared memory outside shmem_request_hook
[2022-05-18 22:48:22 JST]    LOCATION:  RequestAddinShmemSpace, ipci.c:72

tuplestore_donestoring() is done storing

Though not directly related to shared libraries, the function tuplestore_donestoring() has enjoyed a run of cargo cult copy'n'paste in core and third-party code spanning almost two decades after it was converted to a no-op compatibility macro back in 2003 (commit dd04e958).

Commit d61a361d expunges remaining tuplestore_donestoring() invocations in the core code, though the compatibility macro is retained. Its continuing presence in other code will do no harm, but as with _PG_fini(), it's pointeless keeping it around.

Posted at 3:24 AM

Post a comment
Name:
*
E-Mail:
address will not be displayed
Homepage:
Comment: