From 63bead18fbfb71e46b4193ac4464740f63fa4295 Mon Sep 17 00:00:00 2001 From: Mark Dilger Date: Tue, 7 Oct 2025 16:49:22 -0700 Subject: [PATCH v2] Assert lwlocks not held during qual evaluation Add assertions in the new push-down quals code that no lwlocks are held, including lwlocks on buffers, during the evaluation of the quals. --- src/backend/access/heap/heapam_valid.c | 2 ++ src/backend/executor/nodeSeqscan.c | 16 ++++++++++++++++ src/backend/storage/lmgr/lwlock.c | 9 +++++++++ src/include/storage/lwlock.h | 6 ++++++ 4 files changed, 33 insertions(+) diff --git a/src/backend/access/heap/heapam_valid.c b/src/backend/access/heap/heapam_valid.c index a05738a9144..00936331109 100644 --- a/src/backend/access/heap/heapam_valid.c +++ b/src/backend/access/heap/heapam_valid.c @@ -123,6 +123,8 @@ HeapKeyTest(HeapTuple tuple, TupleDesc tupdesc, int nkeys, ScanKey keys) int cur_nkeys = nkeys; ScanKey cur_key = keys; + AssertNoLWLockHeldByMe("HeapKeyTest"); + for (; cur_nkeys--; cur_key++) { Datum atp; diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 210d4cb84e0..ea80208b4ee 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -65,6 +65,8 @@ ExecSeqBuildScanKeys(PlanState *planstate, List *quals, int *numScanKeys, int n_runtime_keys; int max_runtime_keys; + AssertNoLWLockHeldByMe("ExecSeqBuildScanKeys"); + n_quals = list_length(quals); /* @@ -396,6 +398,8 @@ SeqNext(SeqScanState *node) ScanDirection direction; TupleTableSlot *slot; + AssertNoLWLockHeldByMe("SeqNext"); + /* * get information from the estate and scan state */ @@ -778,6 +782,8 @@ ExecReScanSeqScan(SeqScanState *node) { TableScanDesc scan; + AssertNoLWLockHeldByMe("ExecReScanSeqScan"); + /* * If we are doing runtime key calculations (ie, any of the scan key * values weren't simple Consts), compute the new key values. But first, @@ -821,6 +827,8 @@ ExecSeqScanEvalRuntimeKeys(ExprContext *econtext, int j; MemoryContext oldContext; + AssertNoLWLockHeldByMe("ExecSeqScanEvalRuntimeKeys"); + /* We want to keep the key values in per-tuple memory */ oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); @@ -881,6 +889,8 @@ ExecSeqScanEstimate(SeqScanState *node, { EState *estate = node->ss.ps.state; + AssertNoLWLockHeldByMe("ExecSeqScanEstimate"); + node->pscan_len = table_parallelscan_estimate(node->ss.ss_currentRelation, estate->es_snapshot); shm_toc_estimate_chunk(&pcxt->estimator, node->pscan_len); @@ -900,6 +910,8 @@ ExecSeqScanInitializeDSM(SeqScanState *node, EState *estate = node->ss.ps.state; ParallelTableScanDesc pscan; + AssertNoLWLockHeldByMe("ExecSeqScanInitializeDSM"); + pscan = shm_toc_allocate(pcxt->toc, node->pscan_len); table_parallelscan_initialize(node->ss.ss_currentRelation, pscan, @@ -931,6 +943,8 @@ ExecSeqScanReInitializeDSM(SeqScanState *node, { ParallelTableScanDesc pscan; + AssertNoLWLockHeldByMe("ExecSeqScanReInitializeDSM"); + pscan = node->ss.ss_currentScanDesc->rs_parallel; table_parallelscan_reinitialize(node->ss.ss_currentRelation, pscan); } @@ -947,6 +961,8 @@ ExecSeqScanInitializeWorker(SeqScanState *node, { ParallelTableScanDesc pscan; + AssertNoLWLockHeldByMe("ExecSeqScanInitializeWorker"); + pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false); node->ss.ss_currentScanDesc = table_beginscan_parallel(node->ss.ss_currentRelation, pscan, diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index ec9c345ffdf..3aed1e3de4c 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -743,6 +743,15 @@ GetLWLockIdentifier(uint32 classId, uint16 eventId) return GetLWTrancheName(eventId); } +#ifdef USE_ASSERT_CHECKING +void +AssertNoLWLockHeldByMe(const char *context) +{ + if (num_held_lwlocks > 0) + elog(ERROR, "In %s: holding %d lightweight locks", context, num_held_lwlocks); +} +#endif + /* * Internal function that tries to atomically acquire the lwlock in the passed * in mode. diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h index 5e717765764..f786b84ba91 100644 --- a/src/include/storage/lwlock.h +++ b/src/include/storage/lwlock.h @@ -146,6 +146,12 @@ extern void InitLWLockAccess(void); extern const char *GetLWLockIdentifier(uint32 classId, uint16 eventId); +#ifdef USE_ASSERT_CHECKING +extern void AssertNoLWLockHeldByMe(const char *context); +#else +#define AssertNoLWLockHeldByMe(context) +#endif + /* * Extensions (or core code) can obtain an LWLocks by calling * RequestNamedLWLockTranche() during postmaster startup. Subsequently, -- 2.39.5 (Apple Git-154)