Skip to content

Commit c53d90b

Browse files
committed
Fix memory leak in pgoutput with relation attribute map
pgoutput caches the attribute map of a relation, that is free()'d only when validating a RelationSyncEntry. However, this code path is not taken when calling any of the SQL functions able to do some logical decoding, like pg_logical_slot_{get,peek}_changes(), leaking some memory into CacheMemoryContext on repeated calls. This is a follow-up of c9b3d49, this time for v13 and v14. The relation attribute map is stored in a dedicated memory context, tracked with a static variable whose state is reset with a MemoryContext reset callback attached to PGOutputData->context. This implementation is similar to the approach taken by cfd6cbc. Reported-by: Masahiko Sawada Author: Vignesh C Reviewed-by: Hou Zhijie Discussion: https://postgr.es/m/CAD21AoDkAhQVSukOfH3_reuF-j4EU0-HxMqU3dU+bSTxsqT14Q@mail.gmail.com Discussion: https://postgr.es/m/CALDaNm1hewNAsZ_e6FF52a=9drmkRJxtEPrzCB6-9mkJyeBBqA@mail.gmail.com Backpatch-through: 13
1 parent f154f02 commit c53d90b

File tree

1 file changed

+20
-10
lines changed

1 file changed

+20
-10
lines changed

src/backend/replication/pgoutput/pgoutput.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@ static bool publications_valid;
6666
static bool in_streaming;
6767

6868
/*
69-
* Private memory context for publication data, created in
70-
* PGOutputData->context when starting pgoutput, and set to NULL when its
71-
* parent context is reset via a dedicated MemoryContextCallback.
69+
* Private memory contexts for publication data and relation attribute
70+
* map, created in PGOutputData->context when starting pgoutput, and set
71+
* to NULL when its parent context is reset via a dedicated
72+
* MemoryContextCallback.
7273
*/
7374
static MemoryContext pubctx = NULL;
75+
static MemoryContext cachectx = NULL;
7476

7577
static List *LoadPublications(List *pubnames);
7678
static void publication_invalidation_cb(Datum arg, int cacheid,
@@ -260,12 +262,14 @@ parse_output_parameters(List *options, PGOutputData *data)
260262
}
261263

262264
/*
263-
* Callback of PGOutputData->context in charge of cleaning pubctx.
265+
* Callback of PGOutputData->context in charge of cleaning pubctx and
266+
* cachectx.
264267
*/
265268
static void
266-
pgoutput_pubctx_reset_callback(void *arg)
269+
pgoutput_ctx_reset_callback(void *arg)
267270
{
268271
pubctx = NULL;
272+
cachectx = NULL;
269273
}
270274

271275
/*
@@ -289,8 +293,13 @@ pgoutput_startup(LogicalDecodingContext *ctx, OutputPluginOptions *opt,
289293
"logical replication publication list context",
290294
ALLOCSET_SMALL_SIZES);
291295

296+
Assert(cachectx == NULL);
297+
cachectx = AllocSetContextCreate(ctx->context,
298+
"logical replication cache context",
299+
ALLOCSET_SMALL_SIZES);
300+
292301
mcallback = palloc0(sizeof(MemoryContextCallback));
293-
mcallback->func = pgoutput_pubctx_reset_callback;
302+
mcallback->func = pgoutput_ctx_reset_callback;
294303
MemoryContextRegisterResetCallback(ctx->context, mcallback);
295304

296305
ctx->output_plugin_private = data;
@@ -489,8 +498,8 @@ maybe_send_schema(LogicalDecodingContext *ctx,
489498
TupleDesc outdesc = RelationGetDescr(ancestor);
490499
MemoryContext oldctx;
491500

492-
/* Map must live as long as the session does. */
493-
oldctx = MemoryContextSwitchTo(CacheMemoryContext);
501+
/* Map must live as long as the logical decoding context. */
502+
oldctx = MemoryContextSwitchTo(cachectx);
494503

495504
/*
496505
* Make copies of the TupleDescs that will live as long as the map
@@ -812,8 +821,8 @@ pgoutput_origin_filter(LogicalDecodingContext *ctx,
812821
/*
813822
* Shutdown the output plugin.
814823
*
815-
* Note, we don't need to clean the data->context and pubctx as they are
816-
* child contexts of the ctx->context so they will be cleaned up by logical
824+
* Note, we don't need to clean the data->context, pubctx and cachectx as they
825+
* are child contexts of the ctx->context so they will be cleaned up by logical
817826
* decoding machinery.
818827
*/
819828
static void
@@ -827,6 +836,7 @@ pgoutput_shutdown(LogicalDecodingContext *ctx)
827836

828837
/* Better safe than sorry */
829838
pubctx = NULL;
839+
cachectx = NULL;
830840
}
831841

832842
/*

0 commit comments

Comments
 (0)