From e4b15b94993555c79d30f0386250973e6b0a2904 Mon Sep 17 00:00:00 2001 From: Shihao Date: Sun, 27 Sep 2026 08:41:43 -0700 Subject: [PATCH v3] Reset waitStart when a lock wait ends PGPROC->waitStart could keep the start time of a lock wait that had already ended, in two ways. RemoveFromWaitQueue() did not clear it, unlike ProcWakeup(). It ends the wait on lock_timeout, query cancel and deadlock. A waiter also releases the partition lock before it stores waitStart, in ProcSleep() or, for the startup process, in ResolveRecoveryConflictWithLock(). If ProcWakeup() grants the lock in between, it clears waitStart too early and the waiter's value stays. A regular backend overwrites the value at its next lock wait, so pg_locks shows the old time only at the start of that wait. The startup process stores waitStart only when it reads zero, so there pg_locks shows the old time for the whole next wait. Fix by clearing waitStart in RemoveFromWaitQueue(), at the end of ProcSleep() and in LockErrorCleanup(). The last one covers a cancel that arrives after the grant, where ProcSleep() errors out before its end. Oversight in 46d6e5f5679. Reported-by: Alex Shapalov Reported-by: Fujii Masao Discussion: https://postgr.es/m/CAPrb+Q+XN=sNusXiUeWmMo2H7Qgq3Y4uPekSSLkHcnCyf7GhXg@mail.gmail.com Discussion: https://postgr.es/m/CAGRkXqQLxZBr-ouVrtaX2utMggi4+TiVMbgH04b_0JLgKryxbA@mail.gmail.com Backpatch-through: 14 --- src/backend/storage/lmgr/lock.c | 1 + src/backend/storage/lmgr/proc.c | 10 ++++++++++ 2 files changed, 11 insertions(+) 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. diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 91fe2766640..f93203916c1 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -871,6 +871,9 @@ LockErrorCleanup(void) GrantAwaitedLock(); } + /* Clear waitStart, for the same reason as at the end of ProcSleep() */ + pg_atomic_write_u64(&MyProc->waitStart, 0); + ResetAwaitedLock(); LWLockRelease(partitionLock); @@ -1744,6 +1747,13 @@ ProcSleep(LOCALLOCK *locallock) } } while (myWaitStatus == PROC_WAIT_STATUS_WAITING); + /* + * The wait is over, so clear waitStart. ProcWakeup() clears it too, but + * it can run before we set waitStart, and then our value would be left + * behind. + */ + pg_atomic_write_u64(&MyProc->waitStart, 0); + /* * Disable the timers, if they are still running. As in LockErrorCleanup, * we must preserve the LOCK_TIMEOUT indicator flag: if a lock timeout has -- 2.37.1 (Apple Git-137.1)