Hi, Thanks for your comments about the v2 patches. I updated to v3 patches.
The main changes are: * remove the AddinShmemInitLock assertion * add the new lock (WaitEventExtensionLock) to wait_event_names.txt * change "static const int wee_hash_XXX_size" to "#define XXX" * simplify worker_spi. I removed codes related to share memory andtry to allocate the new wait event before waiting per background worker.
* change to elog from ereport because the errors are for developers. * revise comments as advised. * fix the request size for shared memory correctly * simplify dblink.c * fix process ordering of WaitEventExtensionNew() as advised to avoid leading illegal state. In addition, I change the followings: * update about custom wait events in sgml. we don't need to use shmem_startup_hook. * change the hash names for readability. (ex. WaitEventExtensionNameHash -> WaitEventExtensionHashById) * fix a bug to fail to get already defined events by names because HASH_BLOBS was specified. HASH_STRINGS is right since the key is C strings. I create a new entry in commitfest for CI testing. (https://commitfest.postgresql.org/44/4494/) Thanks for closing the former entry. (https://commitfest.postgresql.org/43/4368/) Regards, -- Masahiro Ikeda NTT DATA CORPORATION
From 234cc7d852aebf78285ccde383f27ea35a27dad2 Mon Sep 17 00:00:00 2001 From: Masahiro Ikeda <mshr.ik...@ntt.com> Date: Thu, 10 Aug 2023 10:44:41 +0900 Subject: [PATCH 2/2] poc: custom wait event for dblink --- contrib/dblink/dblink.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 41e1f6c91d..b7158ecd4f 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -129,6 +129,7 @@ static void restoreLocalGucs(int nestlevel); /* Global */ static remoteConn *pconn = NULL; static HTAB *remoteConnHash = NULL; +static uint32 wait_event_info = 0; /* * Following is list that holds multiple remote connections. @@ -203,7 +204,9 @@ dblink_get_conn(char *conname_or_str, dblink_connstr_check(connstr); /* OK to make connection */ - conn = libpqsrv_connect(connstr, WAIT_EVENT_EXTENSION); + if (wait_event_info == 0) + wait_event_info = WaitEventExtensionNew("dblink_get_con"); + conn = libpqsrv_connect(connstr, wait_event_info); if (PQstatus(conn) == CONNECTION_BAD) { -- 2.25.1
From 07bbff06a0f58f08d313c02cbb4104ad1db2a0e9 Mon Sep 17 00:00:00 2001 From: Masahiro Ikeda <mshr.ik...@ntt.com> Date: Thu, 10 Aug 2023 10:43:34 +0900 Subject: [PATCH 1/2] Change to manage custom wait events in shared hash Currently, names of the custom wait event must be registered per backends. This patch relaxes the constraints by store the wait events and their names in hash tables in shared memory. So, all backends can look up the wait event names on pg_stat_activity view without additional processing by extensions. In addition, extensions which do not use shared memory for their use can define custom wait events because WaitEventExtensionNew() will never allocate new one if the wait event associated to the name is already allocated. It use hash table to identify uniqueness. --- doc/src/sgml/monitoring.sgml | 7 +- doc/src/sgml/xfunc.sgml | 26 +-- src/backend/storage/lmgr/lwlocknames.txt | 1 + src/backend/utils/activity/wait_event.c | 219 +++++++++++------- .../utils/activity/wait_event_names.txt | 1 + src/include/utils/wait_event.h | 17 +- .../modules/worker_spi/t/001_worker_spi.pl | 18 +- .../modules/worker_spi/worker_spi--1.0.sql | 5 - src/test/modules/worker_spi/worker_spi.c | 109 +-------- 9 files changed, 165 insertions(+), 238 deletions(-) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index f4fc5d814f..19181832d7 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -1121,10 +1121,9 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i <literal>LWLock</literal> types to the list shown in <xref linkend="wait-event-extension-table"/> and <xref linkend="wait-event-lwlock-table"/>. In some cases, the name - assigned by an extension will not be available in all server processes; - so an <literal>Extension</literal> or <literal>LWLock</literal> wait - event might be reported as just - <quote><literal>extension</literal></quote> rather than the + of <literal>LWLock</literal> assigned by an extension will not be + available in all server processes; so an wait event might be reported + as just <quote><literal>extension</literal></quote> rather than the extension-assigned name. </para> </note> diff --git a/doc/src/sgml/xfunc.sgml b/doc/src/sgml/xfunc.sgml index d6345a775b..281c178b0e 100644 --- a/doc/src/sgml/xfunc.sgml +++ b/doc/src/sgml/xfunc.sgml @@ -3454,33 +3454,15 @@ if (!ptr) </sect2> <sect2 id="xfunc-addin-wait-events"> - <title>Shared Memory and Custom Wait Events</title> + <title>Custom Wait Events</title> <para> Add-ins can define custom wait events under the wait event type - <literal>Extension</literal>. The add-in's shared library must be - preloaded by specifying it in <literal>shared_preload_libraries</literal>, - and register a <literal>shmem_request_hook</literal> and a - <literal>shmem_startup_hook</literal> in its - <function>_PG_init</function> function. - <literal>shmem_request_hook</literal> can request a shared memory size - to be later used at startup by calling: + <literal>Extension</literal> by calling: <programlisting> -void RequestAddinShmemSpace(int size) -</programlisting> - </para> - <para> - <literal>shmem_startup_hook</literal> can allocate in shared memory - custom wait events by calling while holding the LWLock - <function>AddinShmemInitLock</function> to avoid any race conditions: -<programlisting> -uint32 WaitEventExtensionNew(void) -</programlisting> - Next, each process needs to associate the wait event allocated previously - to a user-facing custom string, which is something done by calling: -<programlisting> -void WaitEventExtensionRegisterName(uint32 wait_event_info, const char *wait_event_name) +uint32 WaitEventExtensionNew(const char *wait_event_name) </programlisting> + The wait event is associated to a user-facing custom string. An example can be found in <filename>src/test/modules/worker_spi</filename> in the PostgreSQL source tree. </para> diff --git a/src/backend/storage/lmgr/lwlocknames.txt b/src/backend/storage/lmgr/lwlocknames.txt index b34b6afecd..7af3e0ba1a 100644 --- a/src/backend/storage/lmgr/lwlocknames.txt +++ b/src/backend/storage/lmgr/lwlocknames.txt @@ -53,3 +53,4 @@ XactTruncationLock 44 # 45 was XactTruncationLock until removal of BackendRandomLock WrapLimitsVacuumLock 46 NotifyQueueTailLock 47 +WaitEventExtensionLock 48 diff --git a/src/backend/utils/activity/wait_event.c b/src/backend/utils/activity/wait_event.c index b3596ece80..d2b21d54a6 100644 --- a/src/backend/utils/activity/wait_event.c +++ b/src/backend/utils/activity/wait_event.c @@ -45,6 +45,42 @@ uint32 *my_wait_event_info = &local_my_wait_event_info; #define WAIT_EVENT_CLASS_MASK 0xFF000000 #define WAIT_EVENT_ID_MASK 0x0000FFFF +/* + * Hash tables for storing custom wait event ids and their names in + * shared memory. + * + * WaitEventExtensionHashById is used to find the name from a event id. + * It enables all backends look up them without additional processing + * per backend. + * + * WaitEventExtensionHashByName is used to find the event id from a name. + * It's used to ensure that duplicated entries won't be registered + * by identify uniqueness by the names + * + * The size of hash table is based on assumption. In most of the case, + * 16 seem to be sufficient. It seems unlikely that the number of entries + * will reach 512. + */ +static HTAB *WaitEventExtensionHashById; /* find names from ids */ +static HTAB *WaitEventExtensionHashByName; /* find ids from names */ + +#define WaitEventExtensionHashInitSize 128 +#define WaitEventExtensionHashMaxSize 512 + +/* hash table entres */ +typedef struct WaitEventExtensionEntryById +{ + uint16 event_id; /* hash key */ + char wait_event_name[NAMEDATALEN]; /* custom wait event name */ +} WaitEventExtensionEntryById; + +typedef struct WaitEventExtensionEntryByName +{ + char wait_event_name[NAMEDATALEN]; /* hash key */ + uint16 event_id; /* wait event id */ +} WaitEventExtensionEntryByName; + + /* dynamic allocation counter for custom wait events in extensions */ typedef struct WaitEventExtensionCounterData { @@ -59,36 +95,38 @@ static WaitEventExtensionCounterData *WaitEventExtensionCounter; #define NUM_BUILTIN_WAIT_EVENT_EXTENSION \ (WAIT_EVENT_EXTENSION_FIRST_USER_DEFINED - WAIT_EVENT_EXTENSION) -/* - * This is indexed by event ID minus NUM_BUILTIN_WAIT_EVENT_EXTENSION, and - * stores the names of all dynamically-created event IDs known to the current - * process. Any unused entries in the array will contain NULL. - */ -static const char **WaitEventExtensionNames = NULL; -static int WaitEventExtensionNamesAllocated = 0; +/* wait event info for extensions */ +#define WAIT_EVENT_EXTENSION_INFO(eventId) (PG_WAIT_EXTENSION | eventId) static const char *GetWaitEventExtensionIdentifier(uint16 eventId); /* - * Return the space for dynamic allocation counter. + * Return the space for dynamic shared hash tables and dynamic allocation counter. */ Size WaitEventExtensionShmemSize(void) { - return sizeof(WaitEventExtensionCounterData); + Size sz; + sz = MAXALIGN(sizeof(WaitEventExtensionCounterData)); + sz = add_size(sz, hash_estimate_size(WaitEventExtensionHashMaxSize, + sizeof(WaitEventExtensionEntryById))); + sz = add_size(sz, hash_estimate_size(WaitEventExtensionHashMaxSize, + sizeof(WaitEventExtensionEntryByName))); + return sz; } /* - * Allocate shmem space for dynamic allocation counter. + * Allocate shmem space for dynamic shared hash and dynamic allocation counter. */ void WaitEventExtensionShmemInit(void) { bool found; + HASHCTL info; WaitEventExtensionCounter = (WaitEventExtensionCounterData *) ShmemInitStruct("WaitEventExtensionCounterData", - WaitEventExtensionShmemSize(), &found); + MAXALIGN(sizeof(WaitEventExtensionCounterData)), &found); if (!found) { @@ -96,21 +134,77 @@ WaitEventExtensionShmemInit(void) WaitEventExtensionCounter->nextId = NUM_BUILTIN_WAIT_EVENT_EXTENSION; SpinLockInit(&WaitEventExtensionCounter->mutex); } + + /* initialize or atatch the hash tables to store custom wait events */ + info.keysize = sizeof(uint16); + info.entrysize = sizeof(WaitEventExtensionEntryById); + WaitEventExtensionHashById = ShmemInitHash("Wait Event Extension hash by id", + WaitEventExtensionHashInitSize, + WaitEventExtensionHashMaxSize, + &info, + HASH_ELEM | HASH_BLOBS); + + info.keysize = sizeof(char[NAMEDATALEN]); + info.entrysize = sizeof(WaitEventExtensionEntryByName); + WaitEventExtensionHashByName = ShmemInitHash("Wait Event Extension hash by name", + WaitEventExtensionHashInitSize, + WaitEventExtensionHashMaxSize, + &info, + HASH_ELEM | HASH_STRINGS); /* key is Null-terminated C strings */ } /* - * Allocate a new event ID and return the wait event. + * Allocate a new event ID and return the wait event info. + * + * If the wait event name is already defined, this don't + * allocate new one, but it return the wait event info + * associated to the name. */ uint32 -WaitEventExtensionNew(void) +WaitEventExtensionNew(const char *wait_event_name) { uint16 eventId; + bool found; + WaitEventExtensionEntryByName *entry_by_name; + WaitEventExtensionEntryById *entry_by_id; + + /* Check the limit of the length of the event name */ + if (strlen(wait_event_name) >= NAMEDATALEN) + elog(ERROR, + "cannot use custom wait event string longer than %u characters", + NAMEDATALEN - 1); - Assert(LWLockHeldByMeInMode(AddinShmemInitLock, LW_EXCLUSIVE)); + /* + * Check the wait event info associated to the name is already defined. + * Return it if so. + */ + LWLockAcquire(WaitEventExtensionLock, LW_SHARED); + entry_by_name = (WaitEventExtensionEntryByName *) + hash_search(WaitEventExtensionHashByName, wait_event_name, + HASH_FIND, &found); + LWLockRelease(WaitEventExtensionLock); + if (found) + return WAIT_EVENT_EXTENSION_INFO(entry_by_name->event_id); + + /* + * Allocate and register a new wait event. But, we need to recheck because + * other processes could already do so while releasing the lock. + */ + LWLockAcquire(WaitEventExtensionLock, LW_EXCLUSIVE); + entry_by_name = (WaitEventExtensionEntryByName *) + hash_search(WaitEventExtensionHashByName, wait_event_name, + HASH_FIND, &found); + /* Recheck */ + if (found) + { + LWLockRelease(WaitEventExtensionLock); + return WAIT_EVENT_EXTENSION_INFO(entry_by_name->event_id); + } + /* Allocate a new event Id */ SpinLockAcquire(&WaitEventExtensionCounter->mutex); - if (WaitEventExtensionCounter->nextId > PG_UINT16_MAX) + if (WaitEventExtensionCounter->nextId >= WaitEventExtensionHashMaxSize) { SpinLockRelease(&WaitEventExtensionCounter->mutex); ereport(ERROR, @@ -122,64 +216,23 @@ WaitEventExtensionNew(void) SpinLockRelease(&WaitEventExtensionCounter->mutex); - return PG_WAIT_EXTENSION | eventId; -} - -/* - * Register a dynamic wait event name for extension in the lookup table - * of the current process. - * - * This routine will save a pointer to the wait event name passed as an argument, - * so the name should be allocated in a backend-lifetime context - * (shared memory, TopMemoryContext, static constant, or similar). - * - * The "wait_event_name" will be user-visible as a wait event name, so try to - * use a name that fits the style for those. - */ -void -WaitEventExtensionRegisterName(uint32 wait_event_info, - const char *wait_event_name) -{ - uint32 classId; - uint16 eventId; - - classId = wait_event_info & WAIT_EVENT_CLASS_MASK; - eventId = wait_event_info & WAIT_EVENT_ID_MASK; - - /* Check the wait event class. */ - if (classId != PG_WAIT_EXTENSION) - ereport(ERROR, - errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid wait event class %u", classId)); - - /* This should only be called for user-defined wait event. */ - if (eventId < NUM_BUILTIN_WAIT_EVENT_EXTENSION) - ereport(ERROR, - errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid wait event ID %u", eventId)); + /* Register the new wait event */ + entry_by_id = (WaitEventExtensionEntryById *) + hash_search(WaitEventExtensionHashById, &eventId, + HASH_ENTER, &found); + Assert(!found); + strlcpy(entry_by_id->wait_event_name, wait_event_name, + sizeof(entry_by_id->wait_event_name)); - /* Convert to array index. */ - eventId -= NUM_BUILTIN_WAIT_EVENT_EXTENSION; + entry_by_name = (WaitEventExtensionEntryByName *) + hash_search(WaitEventExtensionHashByName, wait_event_name, + HASH_ENTER, &found); + Assert(!found); + entry_by_name->event_id = eventId; - /* If necessary, create or enlarge array. */ - if (eventId >= WaitEventExtensionNamesAllocated) - { - uint32 newalloc; - - newalloc = pg_nextpower2_32(Max(8, eventId + 1)); - - if (WaitEventExtensionNames == NULL) - WaitEventExtensionNames = (const char **) - MemoryContextAllocZero(TopMemoryContext, - newalloc * sizeof(char *)); - else - WaitEventExtensionNames = - repalloc0_array(WaitEventExtensionNames, const char *, - WaitEventExtensionNamesAllocated, newalloc); - WaitEventExtensionNamesAllocated = newalloc; - } + LWLockRelease(WaitEventExtensionLock); - WaitEventExtensionNames[eventId] = wait_event_name; + return WAIT_EVENT_EXTENSION_INFO(eventId); } /* @@ -188,23 +241,29 @@ WaitEventExtensionRegisterName(uint32 wait_event_info, static const char * GetWaitEventExtensionIdentifier(uint16 eventId) { + bool found; + WaitEventExtensionEntryById *entry; + /* Built-in event? */ if (eventId < NUM_BUILTIN_WAIT_EVENT_EXTENSION) return "Extension"; + /* It is a user-defined wait event, so lookup hash table. */ + LWLockAcquire(WaitEventExtensionLock, LW_SHARED); + entry = (WaitEventExtensionEntryById *) + hash_search(WaitEventExtensionHashById, &eventId, + HASH_FIND, &found); + LWLockRelease(WaitEventExtensionLock); + /* - * It is a user-defined wait event, so look at WaitEventExtensionNames[]. - * However, it is possible that the name has never been registered by - * calling WaitEventExtensionRegisterName() in the current process, in - * which case give up and return "extension". + * The entry must be stored because it's registered in + * WaitEventExtensionNew(). */ - eventId -= NUM_BUILTIN_WAIT_EVENT_EXTENSION; - - if (eventId >= WaitEventExtensionNamesAllocated || - WaitEventExtensionNames[eventId] == NULL) - return "extension"; + if (!entry) + elog(ERROR, "could not find the name for custom wait event ID %u", + eventId); - return WaitEventExtensionNames[eventId]; + return entry->wait_event_name; } diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt index 2ea4789b00..a4e5c80bc0 100644 --- a/src/backend/utils/activity/wait_event_names.txt +++ b/src/backend/utils/activity/wait_event_names.txt @@ -317,6 +317,7 @@ WAIT_EVENT_DOCONLY LogicalRepWorker "Waiting to read or update the state of logi WAIT_EVENT_DOCONLY XactTruncation "Waiting to execute <function>pg_xact_status</function> or update the oldest transaction ID available to it." WAIT_EVENT_DOCONLY WrapLimitsVacuum "Waiting to update limits on transaction id and multixact consumption." WAIT_EVENT_DOCONLY NotifyQueueTail "Waiting to update limit on <command>NOTIFY</command> message storage." +WAIT_EVENT_DOCONLY WaitEventExtension "Waiting to read or update custom wait events information for extensions." WAIT_EVENT_DOCONLY XactBuffer "Waiting for I/O on a transaction status SLRU buffer." WAIT_EVENT_DOCONLY CommitTsBuffer "Waiting for I/O on a commit timestamp SLRU buffer." diff --git a/src/include/utils/wait_event.h b/src/include/utils/wait_event.h index aad8bc08fa..51a0b83b79 100644 --- a/src/include/utils/wait_event.h +++ b/src/include/utils/wait_event.h @@ -44,12 +44,13 @@ extern PGDLLIMPORT uint32 *my_wait_event_info; * Use this category when the server process is waiting for some condition * defined by an extension module. * - * Extensions can define their own wait events in this category. First, - * they should call WaitEventExtensionNew() to get one or more wait event - * IDs that are allocated from a shared counter. These can be used directly - * with pgstat_report_wait_start() or equivalent. Next, each individual - * process should call WaitEventExtensionRegisterName() to associate a wait - * event string to the number allocated previously. + * Extensions can define their own wait events in this category. They should + * call WaitEventExtensionNew() with a wait event string. If the wait event + * associated the string is already allocated, it returns the wait event info. + * If not, it will get one wait event ID that is allocated from a shared counter, + * associate the string to the number in the shared dynamic hash and return the + * wait event info. The string can be used directly with pgstat_report_wait_start() + * or equivalent. */ typedef enum { @@ -60,9 +61,7 @@ typedef enum extern void WaitEventExtensionShmemInit(void); extern Size WaitEventExtensionShmemSize(void); -extern uint32 WaitEventExtensionNew(void); -extern void WaitEventExtensionRegisterName(uint32 wait_event_info, - const char *wait_event_name); +extern uint32 WaitEventExtensionNew(const char *wait_event_name); /* ---------- * pgstat_report_wait_start() - diff --git a/src/test/modules/worker_spi/t/001_worker_spi.pl b/src/test/modules/worker_spi/t/001_worker_spi.pl index c3e7f5fbe6..26b8a49bec 100644 --- a/src/test/modules/worker_spi/t/001_worker_spi.pl +++ b/src/test/modules/worker_spi/t/001_worker_spi.pl @@ -39,25 +39,11 @@ $node->poll_query_until('postgres', $result = $node->safe_psql('postgres', 'SELECT * FROM schema4.counted;'); is($result, qq(total|1), 'dynamic bgworker correctly consumed tuple data'); -# Check the wait event used by the dynamic bgworker. For a session without -# the state in shared memory known, the default of "extension" is the value -# waited on. +# Check the wait event used by the dynamic bgworker. $result = $node->poll_query_until( 'postgres', qq[SELECT wait_event FROM pg_stat_activity WHERE backend_type ~ 'worker_spi';], - 'extension'); -is($result, 1, 'dynamic bgworker has reported "extension" as wait event'); - -# If the shared memory state is loaded (here with worker_spi_init within -# the same connection as the one querying pg_stat_activity), the wait -# event is the custom one. -# The expected result is a special pattern here with a newline coming from the -# first query where the shared memory state is set. -$result = $node->poll_query_until( - 'postgres', - qq[SELECT worker_spi_init(); SELECT wait_event FROM pg_stat_activity WHERE backend_type ~ 'worker_spi';], - qq[ -worker_spi_main]); + qq[worker_spi_main]); is($result, 1, 'dynamic bgworker has reported "worker_spi_main" as wait event'); diff --git a/src/test/modules/worker_spi/worker_spi--1.0.sql b/src/test/modules/worker_spi/worker_spi--1.0.sql index f13f7e0f98..e9d5b07373 100644 --- a/src/test/modules/worker_spi/worker_spi--1.0.sql +++ b/src/test/modules/worker_spi/worker_spi--1.0.sql @@ -7,8 +7,3 @@ CREATE FUNCTION worker_spi_launch(pg_catalog.int4) RETURNS pg_catalog.int4 STRICT AS 'MODULE_PATHNAME' LANGUAGE C; - -CREATE FUNCTION worker_spi_init() -RETURNS VOID STRICT -AS 'MODULE_PATHNAME' -LANGUAGE C; diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c index c4317351ce..56e492dd4b 100644 --- a/src/test/modules/worker_spi/worker_spi.c +++ b/src/test/modules/worker_spi/worker_spi.c @@ -44,33 +44,17 @@ PG_MODULE_MAGIC; -PG_FUNCTION_INFO_V1(worker_spi_init); PG_FUNCTION_INFO_V1(worker_spi_launch); PGDLLEXPORT void worker_spi_main(Datum main_arg) pg_attribute_noreturn(); -/* Shared memory state */ -typedef struct worker_spi_state -{ - /* the wait event defined during initialization phase */ - uint32 wait_event; -} worker_spi_state; - -static worker_spi_state *wsstate = NULL; /* pointer to shared memory */ - -static shmem_request_hook_type prev_shmem_request_hook = NULL; -static shmem_request_hook_type prev_shmem_startup_hook = NULL; - -static void worker_spi_shmem_request(void); -static void worker_spi_shmem_startup(void); -static void worker_spi_shmem_init(void); -static Size worker_spi_memsize(void); - /* GUC variables */ static int worker_spi_naptime = 10; static int worker_spi_total_workers = 2; static char *worker_spi_database = NULL; +/* Local variables */ +static uint32 worker_spi_wait_event = 0; typedef struct worktable { @@ -78,63 +62,6 @@ typedef struct worktable const char *name; } worktable; -static void -worker_spi_shmem_request(void) -{ - if (prev_shmem_request_hook) - prev_shmem_request_hook(); - - RequestAddinShmemSpace(worker_spi_memsize()); -} - -static void -worker_spi_shmem_startup(void) -{ - if (prev_shmem_startup_hook) - prev_shmem_startup_hook(); - - worker_spi_shmem_init(); -} - -static Size -worker_spi_memsize(void) -{ - return MAXALIGN(sizeof(worker_spi_state)); -} - -/* - * Initialize the shared memory state of worker_spi. - * - * This routine allocates a new wait event when called the first time. - * On follow-up calls, the name of the wait event associated with the - * existing shared memory state is registered. - */ -static void -worker_spi_shmem_init(void) -{ - bool found; - - wsstate = NULL; - - /* Create or attach to the shared memory state */ - LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); - wsstate = ShmemInitStruct("worker_spi State", - sizeof(worker_spi_state), - &found); - - /* Define a new wait event */ - if (!found) - wsstate->wait_event = WaitEventExtensionNew(); - - LWLockRelease(AddinShmemInitLock); - - /* - * Register the wait event in the lookup table of the current process. - */ - WaitEventExtensionRegisterName(wsstate->wait_event, "worker_spi_main"); - return; -} - /* * Initialize workspace for a worker process: create the schema if it doesn't * already exist. @@ -224,9 +151,6 @@ worker_spi_main(Datum main_arg) /* We're now ready to receive signals */ BackgroundWorkerUnblockSignals(); - /* Create (if necessary) and attach to our shared memory area. */ - worker_spi_shmem_init(); - /* Connect to our database */ BackgroundWorkerInitializeConnection(worker_spi_database, NULL, 0); @@ -268,6 +192,10 @@ worker_spi_main(Datum main_arg) { int ret; + /* First time, allocate or get the custom wait event */ + if (worker_spi_wait_event == 0) + worker_spi_wait_event = WaitEventExtensionNew("worker_spi_main"); + /* * Background workers mustn't call usleep() or any direct equivalent: * instead, they may wait on their process latch, which sleeps as @@ -277,7 +205,7 @@ worker_spi_main(Datum main_arg) (void) WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, worker_spi_naptime * 1000L, - wsstate->wait_event); + worker_spi_wait_event); ResetLatch(MyLatch); CHECK_FOR_INTERRUPTS(); @@ -406,11 +334,6 @@ _PG_init(void) MarkGUCPrefixReserved("worker_spi"); - prev_shmem_request_hook = shmem_request_hook; - shmem_request_hook = worker_spi_shmem_request; - prev_shmem_startup_hook = shmem_startup_hook; - shmem_startup_hook = worker_spi_shmem_startup; - /* set up common data for all our workers */ memset(&worker, 0, sizeof(worker)); worker.bgw_flags = BGWORKER_SHMEM_ACCESS | @@ -434,21 +357,6 @@ _PG_init(void) } } -/* - * Wrapper to initialize a session with the shared memory state - * used by this module. This is a convenience routine to be able to - * see the custom wait event stored in shared memory without loading - * through shared_preload_libraries. - */ -Datum -worker_spi_init(PG_FUNCTION_ARGS) -{ - /* Create (if necessary) and attach to our shared memory area. */ - worker_spi_shmem_init(); - - PG_RETURN_VOID(); -} - /* * Dynamically launch an SPI worker. */ @@ -461,9 +369,6 @@ worker_spi_launch(PG_FUNCTION_ARGS) BgwHandleStatus status; pid_t pid; - /* Create (if necessary) and attach to our shared memory area. */ - worker_spi_shmem_init(); - memset(&worker, 0, sizeof(worker)); worker.bgw_flags = BGWORKER_SHMEM_ACCESS | BGWORKER_BACKEND_DATABASE_CONNECTION; -- 2.25.1