From: Tom Lane Date: Tue, 4 Jun 2013 18:59:02 +0000 (-0400) Subject: Fix memory leak in LogStandbySnapshot(). X-Git-Tag: REL9_0_14~52 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c28bfb35ef6ce9e9d82da00008554d0fc9c4a7fc;p=thirdparty%2Fpostgresql.git Fix memory leak in LogStandbySnapshot(). The array allocated by GetRunningTransactionLocks() needs to be pfree'd when we're done with it. Otherwise we leak some memory during each checkpoint, if wal_level = hot_standby. This manifests as memory bloat in the checkpointer process, or in bgwriter in versions before we made the checkpointer separate. Reported and fixed by Naoya Anzai. Back-patch to 9.0 where the issue was introduced. In passing, improve comments for GetRunningTransactionLocks(), and add an Assert that we didn't overrun the palloc'd array. --- diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c index 1a5481177ad..1db951d1fbc 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -879,16 +879,11 @@ LogStandbySnapshot(void) /* * Get details of any AccessExclusiveLocks being held at the moment. - * - * XXX GetRunningTransactionLocks() currently holds a lock on all - * partitions though it is possible to further optimise the locking. By - * reference counting locks and storing the value on the ProcArray entry - * for each backend we can easily tell if any locks need recording without - * trying to acquire the partition locks and scanning the lock table. */ locks = GetRunningTransactionLocks(&nlocks); if (nlocks > 0) LogAccessExclusiveLocks(nlocks, locks); + pfree(locks); /* * Log details of all in-progress transactions. This should be the last diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index e9afc7c0093..1020756ae34 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -2360,18 +2360,26 @@ GetLockStatusData(void) } /* - * Returns a list of currently held AccessExclusiveLocks, for use - * by GetRunningTransactionData(). + * Returns a list of currently held AccessExclusiveLocks, for use by + * LogStandbySnapshot(). The result is a palloc'd array, + * with the number of elements returned into *nlocks. + * + * XXX This currently takes a lock on all partitions of the lock table, + * but it's possible to do better. By reference counting locks and storing + * the value in the ProcArray entry for each backend we could tell if any + * locks need recording without having to acquire the partition locks and + * scan the lock table. Whether that's worth the additional overhead + * is pretty dubious though. */ xl_standby_lock * GetRunningTransactionLocks(int *nlocks) { + xl_standby_lock *accessExclusiveLocks; PROCLOCK *proclock; HASH_SEQ_STATUS seqstat; int i; int index; int els; - xl_standby_lock *accessExclusiveLocks; /* * Acquire lock on the entire shared lock data structure. @@ -2428,6 +2436,8 @@ GetRunningTransactionLocks(int *nlocks) } } + Assert(index <= els); + /* * And release locks. We do this in reverse order for two reasons: (1) * Anyone else who needs more than one of the locks will be trying to lock