diff --git a/src/postgres/src/backend/utils/cache/relcache.c b/src/postgres/src/backend/utils/cache/relcache.c index 781e8f9ea3b3..adfefa12f529 100644 --- a/src/postgres/src/backend/utils/cache/relcache.c +++ b/src/postgres/src/backend/utils/cache/relcache.c @@ -1890,6 +1890,8 @@ YbCompleteAttrProcessingImpl(const YbAttrProcessorState *state) /* Set up constraint/default info */ if (constr->has_not_null || ndef > 0 || attrmiss || relation->rd_rel->relchecks) { + if (relation->rd_att->constr) + pfree(relation->rd_att->constr); relation->rd_att->constr = constr; if (ndef > 0) /* DEFAULTs */ diff --git a/src/postgres/src/backend/utils/cache/yb_inheritscache.c b/src/postgres/src/backend/utils/cache/yb_inheritscache.c index 5494623a393f..ba663e0f3cf1 100644 --- a/src/postgres/src/backend/utils/cache/yb_inheritscache.c +++ b/src/postgres/src/backend/utils/cache/yb_inheritscache.c @@ -226,7 +226,6 @@ void YbPreloadPgInheritsCache() { Assert(YbPgInheritsCache); - MemoryContext oldcxt = MemoryContextSwitchTo(CacheMemoryContext); Relation relation = heap_open(InheritsRelationId, AccessShareLock); HeapTuple inheritsTuple; @@ -253,13 +252,13 @@ YbPreloadPgInheritsCache() entry->refcount = 1; entry->parentOid = parentOid; } - + MemoryContext oldcxt = MemoryContextSwitchTo(CacheMemoryContext); HeapTuple copy_inheritsTuple = heap_copytuple(inheritsTuple); entry->childTuples = lappend(entry->childTuples, copy_inheritsTuple); + MemoryContextSwitchTo(oldcxt); } systable_endscan(scan); heap_close(relation, AccessShareLock); - MemoryContextSwitchTo(oldcxt); } YbPgInheritsCacheEntry diff --git a/src/yb/yql/pgwrapper/pg_libpq-test.cc b/src/yb/yql/pgwrapper/pg_libpq-test.cc index a60e97aeae15..7979f26b8912 100644 --- a/src/yb/yql/pgwrapper/pg_libpq-test.cc +++ b/src/yb/yql/pgwrapper/pg_libpq-test.cc @@ -3881,6 +3881,30 @@ TEST_F(PgLibPqTest, TempTableMultiNodeNamespaceConflict) { ASSERT_EQ(rows, (decltype(rows){4, 5, 6})); } +TEST_F(PgLibPqTest, CatalogCacheMemoryLeak) { + auto conn1 = ASSERT_RESULT(Connect()); + auto conn2 = ASSERT_RESULT(Connect()); + auto query = "SELECT total_bytes, used_bytes FROM " + "pg_get_backend_memory_contexts() " + "WHERE name = 'CacheMemoryContext'"s; + string stable_result; + for (int i = 0; i < 20; i++) { + BumpCatalogVersion(1, &conn1); + // Wait for heartbeat to propagate the new catalog version to trigger + // catalog cache refresh on conn2. + SleepFor(2s); + auto result = ASSERT_RESULT(conn2.FetchAllAsString(query)); + LOG(INFO) << "result: " << result; + if (stable_result.empty()) { + stable_result = result; + } else { + // If each catalog cache refresh had a memory leak in cache memory, + // then this assertion would fail. + ASSERT_EQ(result, stable_result); + } + } +} + class PgBackendsSessionExpireTest : public LibPqTestBase { public: void UpdateMiniClusterOptions(ExternalMiniClusterOptions* options) override {