From 3695caaa087faac36347847052cecf6c1d133956 Mon Sep 17 00:00:00 2001
From: Vignesh <vignesh21@gmail.com>
Date: Tue, 10 Dec 2024 07:28:38 +0530
Subject: [PATCH v1] Fix memory leak in pgoutput with static memory context.

The pgoutput module caches publication names in a list and frees it upon
invalidation.  However, the code forgot to free the actual publication
names within the list elements, as publication names are pstrdup()'d in
GetPublication().  This would cause memory to leak in
CacheMemoryContext, bloating it over time as this context is not
cleaned.

This is a problem for WAL senders running for a long time, as an
accumulation of invalidation requests would bloat its cache memory
usage.  A second case, where this leak is easier to see, involves a
backend calling SQL functions like pg_logical_slot_{get,peek}_changes()
which create a new decoding context with each execution.  More
publications create more bloat.

To address this, this commit adds a new static memory context and
resets it each time the publication names cache is invalidated. This
ensures that the lifespan of the publication names aligns with that of
the logical decoding context.
---
 src/backend/replication/pgoutput/pgoutput.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/backend/replication/pgoutput/pgoutput.c b/src/backend/replication/pgoutput/pgoutput.c
index df2ea94d46..78c81888c4 100644
--- a/src/backend/replication/pgoutput/pgoutput.c
+++ b/src/backend/replication/pgoutput/pgoutput.c
@@ -1071,9 +1071,16 @@ get_rel_sync_entry(PGOutputData *data, Oid relid)
 		/* Reload publications if needed before use. */
 		if (!publications_valid)
 		{
-			oldctx = MemoryContextSwitchTo(CacheMemoryContext);
-			if (data->publications)
-				list_free_deep(data->publications);
+			static MemoryContext pubctx = NULL;
+
+			if (pubctx == NULL)
+				pubctx = AllocSetContextCreate(CacheMemoryContext,
+											   "logical replication publication list context",
+											   ALLOCSET_SMALL_SIZES);
+			else
+				MemoryContextReset(pubctx);
+
+			oldctx = MemoryContextSwitchTo(pubctx);
 
 			data->publications = LoadPublications(data->publication_names);
 			MemoryContextSwitchTo(oldctx);
-- 
2.43.0

