1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Prevent stale pg_locks.waitstart values

Previously, pg_locks.waitstart could report the start time of a previous
lock wait for a new wait. For a regular backend, this could happen briefly
before the new start time was stored. On a standby, the startup process could
show the old time throughout the next wait, making it appear to have started
earlier than it did.

This happened because PGPROC->waitStart could remain set after a previous
wait in two cases. First, RemoveFromWaitQueue() did not clear it when a wait
was canceled due to a lock timeout, cancellation, or deadlock. Second, even
after a successful lock grant, ProcWakeup() could clear it before the waiter
stored its new start time.

Fix this by clearing waitStart in RemoveFromWaitQueue() when a failed wait
is removed, at the end of ProcSleep() to handle writes made after
ProcWakeup() cleared it, and in LockErrorCleanup() when an error bypasses
the ProcSleep() reset. This prevents pg_locks.waitstart from showing the
previous wait's time for a new wait.

Backpatch to all supported versions.

Author: Shihao Zhong <zhong950419@gmail.com>
Reported-by: Alex Shapalov <shapalov@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Reviewed-by: Andrew Krylosov <krylosov.andrew@gmail.com>
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
This commit is contained in:
Fujii Masao
2026-09-28 14:22:04 +09:00
parent 3eff6531d1
commit edfa6c8fcb
2 changed files with 10 additions and 0 deletions

View File

@@ -1956,6 +1956,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.

View File

@@ -766,6 +766,9 @@ LockErrorCleanup(void)
GrantAwaitedLock();
}
/* An error can bypass ProcSleep()'s reset, so clear waitStart here */
pg_atomic_write_u64(&MyProc->waitStart, 0);
lockAwaited = NULL;
LWLockRelease(partitionLock);
@@ -1664,6 +1667,12 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
}
} while (myWaitStatus == PROC_WAIT_STATUS_WAITING);
/*
* Clear waitStart after the wait, as we may have set it after
* ProcWakeup() cleared it.
*/
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