diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c index cc42946..db7c2c5 100644 --- a/src/backend/executor/execParallel.c +++ b/src/backend/executor/execParallel.c @@ -486,7 +486,7 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate, int nworkers) shm_toc_insert(pcxt->toc, PARALLEL_KEY_DSA, area_space); pei->area = dsa_create_in_place(area_space, dsa_minsize, LWTRANCHE_PARALLEL_QUERY_DSA, - "parallel_query_dsa", + NULL, pcxt->seg); } diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index cf6ae88..6c377c2 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -508,6 +508,7 @@ RegisterLWLockTranches(void) LWLockRegisterTranche(LWTRANCHE_LOCK_MANAGER, "lock_manager"); LWLockRegisterTranche(LWTRANCHE_PREDICATE_LOCK_MANAGER, "predicate_lock_manager"); + LWLockRegisterTranche(LWTRANCHE_PARALLEL_QUERY_DSA, "parallel_query_dsa"); /* Register named tranches. */ for (i = 0; i < NamedLWLockTrancheRequests; i++) @@ -583,7 +584,8 @@ LWLockNewTrancheId(void) * Register a tranche ID in the lookup table for the current process. This * routine will save a pointer to the tranche name passed as an argument, * so the name should be allocated in a backend-lifetime context - * (TopMemoryContext, static variable, or similar). + * (TopMemoryContext, static variable, or similar), unless it is explicitly + * deregistered at an appropriate time. */ void LWLockRegisterTranche(int tranche_id, char *tranche_name) @@ -609,6 +611,20 @@ LWLockRegisterTranche(int tranche_id, char *tranche_name) } /* + * Deregister a tranche ID that was previously registered with + * LWLockRegisterTranche. + */ +void +LWLockDeregisterTranche(int tranche_id) +{ + Assert(LWLockTrancheArray != NULL); + Assert(tranche_id < LWLockTranchesAllocated); + Assert(LWLockTrancheArray[tranche_id] != NULL); + + LWLockTrancheArray[tranche_id] = NULL; +} + +/* * RequestNamedLWLockTranche * Request that extra LWLocks be allocated during postmaster * startup. diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c index 988a297..b5a2449 100644 --- a/src/backend/utils/mmgr/dsa.c +++ b/src/backend/utils/mmgr/dsa.c @@ -421,7 +421,10 @@ static void check_for_freed_segments(dsa_area *area); * when possible matters, and we have no provision for recycling them. So, * we require the caller to provide one. The caller must also provide the * tranche name, so that we can distinguish LWLocks belonging to different - * DSAs. + * DSAs. The exception is that if the tranche has already been registered by + * the caller, a NULL pointer should be passed in; in that case, DSA will not + * register and deregister the tranche. If it is non-NULL, tranche_name must + * not be a zero-length string. */ dsa_area * dsa_create(int tranche_id, const char *tranche_name) @@ -626,6 +629,16 @@ dsa_release_in_place(void *place) dsm_unpin_segment(handle); } } + + /* + * If a tranche name was passed in to 'create', then this process has + * registered it. In that case we had better deregister it, or the + * tranche name table will finish up pointing to memory that is about to + * go away. + */ + if (control->lwlock_tranche_name[0] != '\0') + LWLockDeregisterTranche(control->lwlock_tranche_id); + LWLockRelease(&control->lock); } @@ -1151,6 +1164,9 @@ create_internal(void *place, size_t size, Size metadata_bytes; int i; + /* Empty string not permitted as we use it as a sentinel value. */ + Assert(tranche_name == NULL || tranche_name[0] != '\0'); + /* Sanity check on the space we have to work in. */ if (size < dsa_minimum_size()) elog(ERROR, "dsa_area space must be at least %zu, but %zu provided", @@ -1192,7 +1208,10 @@ create_internal(void *place, size_t size, control->refcnt = 1; control->freed_segment_counter = 0; control->lwlock_tranche_id = tranche_id; - strlcpy(control->lwlock_tranche_name, tranche_name, DSA_MAXLEN); + if (tranche_name != NULL) + strlcpy(control->lwlock_tranche_name, tranche_name, DSA_MAXLEN); + else + control->lwlock_tranche_name[0] = '\0'; /* * Create the dsa_area object that this backend will use to access the @@ -1204,8 +1223,9 @@ create_internal(void *place, size_t size, area->mapping_pinned = false; memset(area->segment_maps, 0, sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS); area->high_segment_index = 0; - LWLockRegisterTranche(control->lwlock_tranche_id, - control->lwlock_tranche_name); + if (control->lwlock_tranche_name[0] != '\0') + LWLockRegisterTranche(control->lwlock_tranche_id, + control->lwlock_tranche_name); LWLockInitialize(&control->lock, control->lwlock_tranche_id); for (i = 0; i < DSA_NUM_SIZE_CLASSES; ++i) LWLockInitialize(DSA_SCLASS_LOCK(area, i), @@ -1262,8 +1282,9 @@ attach_internal(void *place, dsm_segment *segment, dsa_handle handle) memset(&area->segment_maps[0], 0, sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS); area->high_segment_index = 0; - LWLockRegisterTranche(control->lwlock_tranche_id, - control->lwlock_tranche_name); + if (control->lwlock_tranche_name[0] != '\0') + LWLockRegisterTranche(control->lwlock_tranche_id, + control->lwlock_tranche_name); /* Set up the segment map for this process's mapping. */ segment_map = &area->segment_maps[0]; diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h index 3ca4db0..2b20b8f 100644 --- a/src/include/storage/lwlock.h +++ b/src/include/storage/lwlock.h @@ -184,6 +184,7 @@ extern LWLockPadded *GetNamedLWLockTranche(const char *tranche_name); */ extern int LWLockNewTrancheId(void); extern void LWLockRegisterTranche(int tranche_id, char *tranche_name); +extern void LWLockDeregisterTranche(int tranche_id); extern void LWLockInitialize(LWLock *lock, int tranche_id); /*