From 8424dfced790a5c2886ac33f9ce33eb57bf99f09 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sun, 31 Oct 2021 15:31:29 -0400 Subject: [PATCH] Avoid O(N^2) behavior when the standby process releases many locks. When replaying a transaction that held many exclusive locks on the primary, a standby server's startup process would expend O(N^2) effort on manipulating the list of locks. This code was fine when written, but commit 1cff1b95a made repetitive list_delete_first() calls inefficient, as explained in its commit message. Fix by just iterating the list normally, and releasing storage only when done. (This'd be inadequate if we needed to recover from an error occurring partway through; but we don't.) Back-patch to v13 where 1cff1b95a came in. Nathan Bossart Discussion: https://postgr.es/m/CD2F0E7F-9822-45EC-A411-AE56F14DEA9F@amazon.com --- src/backend/storage/ipc/standby.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index aeecaf6cab..a3ceec88a1 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -986,9 +986,11 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid) static void StandbyReleaseLockList(List *locks) { - while (locks) + ListCell *lc; + + foreach(lc, locks) { - xl_standby_lock *lock = (xl_standby_lock *) linitial(locks); + xl_standby_lock *lock = (xl_standby_lock *) lfirst(lc); LOCKTAG locktag; elog(trace_recovery(DEBUG4), @@ -1002,9 +1004,9 @@ StandbyReleaseLockList(List *locks) lock->xid, lock->dbOid, lock->relOid); Assert(false); } - pfree(lock); - locks = list_delete_first(locks); } + + list_free_deep(locks); } static void