From 11670ae7c9f81eab782898deb492bb541d95005a Mon Sep 17 00:00:00 2001
From: Shihao <zhong950419@gmail.com>
Date: Wed, 23 Sep 2026 21:04:11 -0400
Subject: [PATCH v2 1/2] Reset waitStart when a lock wait fails

ProcWakeup() clears PGPROC->waitStart when a lock is granted.
RemoveFromWaitQueue() does not. It ends the wait on lock_timeout, query
cancel and deadlock, so after any of those the backend keeps the old
start time until its next lock wait overwrites it.

pg_locks shows waitstart only for ungranted locks, which hides this
most of the time. It still leaks in one window. The next wait joins
the queue before ProcSleep() stores the new waitStart, and in between
pg_locks reports the start time of the earlier failed wait. The comment
in ProcSleep() says waitstart reads NULL there.

Fix by clearing waitStart in RemoveFromWaitQueue(), the same way
ProcWakeup() does.

Oversight in 46d6e5f5679.

Reported-by: Alex Shapalov <shapalov@gmail.com>
Discussion: https://postgr.es/m/CAPrb+Q+XN=sNusXiUeWmMo2H7Qgq3Y4uPekSSLkHcnCyf7GhXg@mail.gmail.com
Backpatch-through: 14
---
 src/backend/storage/lmgr/lock.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 00978168bbf..52fdb656ae8 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -2105,6 +2105,7 @@ RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode)
 	proc->waitLock = NULL;
 	proc->waitProcLock = NULL;
 	proc->waitStatus = PROC_WAIT_STATUS_ERROR;
+	pg_atomic_write_u64(&proc->waitStart, 0);
 
 	/*
 	 * Delete the proclock immediately if it represents no already-held locks.
-- 
2.37.1 (Apple Git-137.1)

